React 学习笔记 —— redux 的使用

安装使用

  • 运行命令

    yarn add redux
    

redux 原理图

在这里插入图片描述

主要流程
  • 组件 通过 Action Creators 分发(dispatch) actionStore
  • Store 将 之前的状态(previousState)、action,传递给 Reducers
  • Reducers 对状态处理后,返回给 Store 新的状态
  • 组件通过 getState() 获取状态
各部分职责
  • Action Creators: 负责生成 action 对象,并分发给 Store
  • Store:负责管理数据,并将 action 传递给 Reducers
  • Reducers: 对数据进行处理、初始化,并返回给 Store

简易demo

  • 目录结构
    在这里插入图片描述

  • /redux/store.js

    import {createStore} from 'redux'
    import test from './test-reducer'
    
    export default createStore(test)	// 接收 reducers,返回 store
    
  • /redux/test-reducer.js

    const initState = 0
    // 初始化时,preState为undefined,因此使用默认值
    export default function handleCount (preState=initState, action) {
        const {type, data} = action
        switch (type) {
            case 'increment':	// 根据对应 type 去修改状态
                return preState + data	// 返回值,作为新状态
            case 'decrement':
                return preState - data
            default:
                return preState	// 返回默认值,即 initState 即 0
        }
    }
    
  • /components/Count/index.jsx

    import React, { Component } from 'react'
    import store from '../../redux/store'
    
    export default class Count extends Component {
        handleAdd = () => {
        	// 通过 dispatch ,分发修改数据的动作(action)
            store.dispatch({type: 'increment', data: 1})
        }
        handleSub = () => {
            store.dispatch({type: 'decrement', data: 1})
        }
        render() {
            return (
                <div>
                    <p>{store.getState()}</p>	{/* 使用getState获取状态 */}
                    <button onClick={this.handleAdd}>+1</button>
                    <button onClick={this.handleSub}>-1</button>
                </div>
            )
        }
    }
    
  • App.js

    import React, { Component } from 'react'
    import Count from './components/Count'
    
    export default class App extends Component {
      render() {
        return (
          <div>
            <Count />	{/*使用 Count*/}
          </div>
        )
      }
    }
    
  • index.js

  • 因为 redux,只负责管理数据,不负责页面更新,因此,当数据变化时,需要自己去更新

  • 方法1,使用store.subscribe订阅状态变动,一旦变动,在组件中调用 this.setState({}) ,触发组件更新

  • 方法2,使用store.subscribe订阅状态变动,一旦变动,重新渲染App组件,一劳永逸

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import store from './redux/store'
    
    ReactDOM.render(<App />, document.getElementById('root'));
    
    // 使用方法二,当状态变化时,直接重新渲染App组件
    store.subscribe(()=>{
      ReactDOM.render(<App />, document.getElementById('root'));
    })
    
  • 效果
    在这里插入图片描述

异步 action

  • store.dispatch(action) 可以传入 object 或者 function

  • 如果 传入的 actionobject,那么称为 同步 action

  • 如果 传入的 actionfunction,那么称为异步 action

  • 但传入的 action 如果是 functionstore无法理解,需要使用 redux-thunk中间件

  • 安装 redux-thunk

    yarn add redux-thunk
    
  • 然后在 store 里应用中间件

    import {createStore, applyMiddleware} from 'redux'
    import thunk from 'redux-thunk'	// 引入 thunk 中间件
    import test from './test-reducer'
    
    export default createStore(test, applyMiddleware(thunk))
    
  • 这样,store 在收到 function 类型的 action 之后,就可以理解了

  • store 会调用这个function action,并传入 dispatch 方法

  • 然后,我们可以在这个函数里面,写一些定时任务,或者ajax请求,但一般还是会调用 dispatch 去分发一个普通的 object action ,来操作数据更新

使用 react-redux

  • redux 不是 facebook 官方出品,为了让程序员更好的在项目中使用 redux,官方出品了 react-redux

  • 安装 react-redux

    yarn add react-redux
    
  • react-redux 中,将组件分为两类:UI组件、容器组件

  • 其中,UI组件,不涉及 redux 相关代码,由 容器组件充当桥梁进行沟通,如下:
    在这里插入图片描述

  • 在以上的demo基础上,进行修改:

  • 目录结构:
    在这里插入图片描述

  • components\Count\index.jsx

    // 没有与 redux 相关的代码
    import React, { Component } from 'react'
    
    export default class Count extends Component {
        handleAdd = () => {
            this.props.increment(1)
        }
        handleSub = () => {
            this.props.decrement(1)
        }
        render() {
            return (
                <div>
                    <p>{this.props.count}</p>
                    <button onClick={this.handleAdd}>+1</button>
                    <button onClick={this.handleSub}>-1</button>
                </div>
            )
        }
    }
    
  • containers/Count/index.jsx

    import CountUI from '../../components/Count'
    import {connect} from 'react-redux'
    
    // 返回值作为 props 传递给 ui组件,一般用来传递 redux 中的状态
    const mapStateToProps = (state) => {
        return {
            count: state
        }
    }
    
    // 返回值作为 props 传递给 ui组件,一般用来传递操作状态的方法
    const mapDispatchToProps = (dispatch) => {
        return {
            increment: (data)=>dispatch({type:'increment', data}),
            decrement: (data)=>dispatch({type:'decrement', data})
        }
    }
    
    // connect 用于连接 UI组件 跟 容器组件
    export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
    // mapDispatchToProps 还可以是一个对象
    /*
    {
        increment: createIncrementAction,   // 值为创建action的函数,react-redux 会执行这个函数,获取action,并自动 dispatch
        decrement: createDecrementAction
    }
    */
    
  • redux\store.js

    // 未变动 
    import {createStore, applyMiddleware} from 'redux'
    import thunk from 'redux-thunk'
    import test from './test-reducer'
    
    export default createStore(test, applyMiddleware(thunk))
    
  • redux\test-reducer.js

    // 未变动 
    const initState = 0
    export default function handleCount (preState=initState, action) {
        const {type, data} = action
        switch (type) {
            case 'increment':
                return preState + data
            case 'decrement':
                return preState - data
            default:
                return preState
        }
    }
    
  • App.js

    import React, { Component } from 'react'
    import Count from './containers/Count'	// 引用并使用 容器组件
    import store from './redux/store'
    
    export default class App extends Component {
      render() {
        return (
          <div>
          	// 传递 store 给 容器组件:连接容器组件 跟 redux
            <Count store={store}/>
          </div>
        )
      }
    }
    
  • index.js

    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    // import store from './redux/store'
    
    ReactDOM.render(<App />, document.getElementById('root'));
    /*	使用 react-redux 后,不需要再自己更新页面
    store.subscribe(()=>{
      ReactDOM.render(<App />, document.getElementById('root'));
    })
    */
    
  • 效果:
    在这里插入图片描述

使用 Provider

  • 在使用 react-redux时,我们需要通过 propsstore,传递给容器组件

  • 但如果容器组件有很多,每个都需要传store,那么对我们来说,会很麻烦

  • 因此,使用 Provider,并给 Provider 传递 store,那么 Provider 会自动传递store给所有 容器组件

  • App.js

    import React, { Component } from 'react'
    import Count from './containers/Count'
    
    export default class App extends Component {
      render() {
        return (
          <div>
            <Count/>	{/* 不需要自己再传递 store */}
          </div>
        )
      }
    }
    
  • index.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import store from './redux/store'
    import {Provider} from 'react-redux'
    
    // 借助  Provider 统一传递
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>
      , document.getElementById('root'));
    

整合UI组件跟容器组件

  • 因为UI 组件并不需要我们渲染,而是直接由 react-reduxconnect方法,生成容器组件
  • 所以,我们常常将 UI 组件 跟 容器组件 写成一个 文件,仅暴露容器组件即可,如下:
  • 通常 整合后的组件,放在 containers 文件夹
  • /containers/Count/index.jsx
    import {connect} from 'react-redux'
    import React, { Component } from 'react'
    
    // UI 组件
    class Count extends Component {
        handleAdd = () => {
            this.props.increment(1)
        }
        handleSub = () => {
            this.props.decrement(1)
        }
        render() {
            return (
                <div>
                    <p>{this.props.count}</p>
                    <button onClick={this.handleAdd}>+1</button>
                    <button onClick={this.handleSub}>-1</button>
                </div>
            )
        }
    }
    
    // 容器组件
    const mapStateToProps = (state) => {
        return {
            count: state
        }
    }
    
    const mapDispatchToProps = (dispatch) => {
        return {
            increment: (data)=>dispatch({type:'increment', data}),
            decrement: (data)=>dispatch({type:'decrement', data})
        }
        
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Count)
    
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tanleiDD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值