react之 第三方 redux 的使用

2022-03-20
4 min read
Featured Image

Redux

redux是什么

  1. redux是一个专门用于做状态管理的JS库(不是react插件库)。

  2. 它可以用在react, angular, vue等项目中, 但基本与react配合使用。

  3. 作用: 集中式管理react应用中多个组件共享的状态。

什么情况下需要使用redux

  1. 某个组件的状态,需要让其他组件可以随时拿到(共享)。

  2. 一个组件需要改变另一个组件的状态(通信)。

  3. 总体原则:能不用就不用, 如果不用比较吃力才考虑使用。

redux原理图的副本

使用 redux

安装: yarn add redux

精简版 - 求和案例

  1. 去除 Count 自身组件状态

  2. src 下建立目录

    • redux
      • store.js
      • count_reducer.js
  3. store.js

    1. 引入 redux 中的 createStore 函数, 创建一个 store
    2. createStore 需要传入一个 reducer
    3. 默认暴露 store 对象
  4. count_reducer.js

    1. reducer 的本质是一个函数, 接收: preState, action 两个参数, 返回加工后的状态
    2. reducer 有两个作用: 初始化状态, 加工状态
    3. reducer 被第一次调用时, 是 store 自动触发的
      1. 传递的 preState 是 undefined
      2. 传递的 action 是随机生成的 type
  5. 在 index.js 中检测 store 中状态的改变, 一旦发生改变, 重选渲染 <App/>

    1. subscribe 函数在 redux 中状态改变的时候后触发.
    2. 因为 redux 只负责管理状态, 没办法通知 react 去重新渲染页面, 只能间接触发.

完整版 - 求和案例

新增文件:

  1. count_action.js 用来专门创建 action 对象, 直接在 需要 dispatch 的地方当做参数传入.

  2. constant.js 用来容易写错的 type 值

异步版 - 求和案例

  • 需要提前引入一个中间件来使用异步:

    1. yarn add redux-thunk,
    2. 在 store.js 中import thunk from 'redux-thunk'
  • action 作为一个对象, 可以是 {type:'type',data:data } , 也可以是一个函数. 当它是函数的时候, 就被称为异步 action.

  • store 的 dispatch 可以做判断:

    1. 如果传入的是同步 action, 那么直接 dispatch 这个对象给 reducer 用.

    2. 如果传入的是异步 action, 那么会给这个函数传入一个 dispatch 函数, 让异步函数来完成及时或者 ajax 等异步工作后, 调用 dispatch , dispatch 需要传入一个同步 action 函数.

react-redux

react-redux模型图

1. 明确两个概念:

  1. UI组件

    1. 只负责 UI 的呈现,不带有任何业务逻辑

    2. 通过props接收数据(一般数据和函数)

    3. 不使用任何 Redux 的 API

    4. 一般保存在components文件夹下

  2. 容器组件

    1. 负责管理数据和业务逻辑,不负责UI的呈现

    2. 使用 Redux 的 API, 和 redux 通信, 将结果给 UI 组件

    3. 一般保存在containers文件夹下

2. 如何创建容器组件

靠 react-redux 的 connect 函数

connect(mapStateToProps, mapDispatchToProps)(UI组件)

  • mapStateToProps: 映射状态, 返回值是一个对象{key:state}
  • mapDispatchToProps: 映射操作状态的方法, 返回值是一个对象{key:function}
    • 可以作为一个对象直接传, 对象就是操作状态的方法.
    • 由 react-redux 来调用 dispatch, 自己不用写(不然要在参数里传 dispatch, 然后在返回的对象里调用 dispatch)

3. 容器组件中的 store

是靠 props 传进去的, 而不是在容器中直接引入的.

react-redux 优化版本

  1. 容器组件和 UI 组件混合成一个组件, UI 组件作为类通过 connect 传入容器, 然后暴露容器

  2. 无需自己给容器传递 store, 不然多个容器每次都要在props键值对传同样的 store={store}, 属于重复性代码. 只需要给 <App /> 外侧包裹一个 <Provider store={store}> , 就可以完成对所有容器的 store 传递. 主要要提前引入 Provider import {Provider} from 'react-redux';

  3. 使用 react-redux 后也不需要自己 subscribe redux 中的状态的改变了, 容器组件可以自动完成这个工作.

  4. mapDispatchToProps 可以简写成一个对象, 不用每次传入 dispatch 并返回函数.

  5. 一个组件和 redux 的交互步骤

    1. 定义 UI 组件 – 不暴露 no leakage

    2. 引入 connect 生成一个容器组件, 并暴露

      connect(state => ({key:value})
             {key:xxxAction}
             )(UI 组件)
      
    3. 在 UI 组件中通过 this.props.xxx 来读写状态

数据共享

  1. 定义一个 Person 组件, 和 Count 组件通过 redux 共享数据
  2. 为 Person 组件同样写一套 reducer, action, 并配置 constant 常量
  3. 重点: Person 的 reducer 和 Count 的 Reducer 要使用 combineReducer 进行合并, 合并后的总状态是一个对象.
  4. 交给 store 的是 reducer, 最后注意在组件去除状态的时候, 状态为一个对象, 所以要取到位.

reducer 必须是纯函数

纯函数就是说同样的输入必须得到同样的输出.

1. 函数体内不能改写参数;
// 不纯
function demo(a) {
  a = 9
}
  1. 不能有网络请求和 IO.
  2. 不能调用 Date.now()或者 Math.random()等不纯的方法.
  3. redux 的 reducer 函数必须是一个纯函数.

关于 prestate 数组的更新, 返回的 state 必须有一个新的数组.

swith(type) {
  case ADD_PERSON:
  	return [data, ...prestate]
}

js 的数组应该是一个地址, 指向堆的存储区域. 如果 prestate 更改前后, 只是数值边了, 地址没变. store 识别不出来, 页面不重新渲染.

一个数组 arr 直接往里推一个单位, arr 的地址是不变的.

let arr = [1,3,5,7,9]
arr.push(10)

最终版

需要把所有 reducer 先引入到 reducer 文件夹下的 index.js, 然后在 store 中引入 index.js

查看项目请点击

Redux 开发者工具

  1. 先在 Chrome 安装扩展

  2. 在 react 开发目录下, yarn add redux-devtools-extension.

  3. 在 store.js 中编写

//创建 rudux 中最为核心的 store 对象
import {createStore, applyMiddleware, combineReducers} from 'redux'
//不加花括号是因为默认暴露了
import countReducer from './reducers/count'
import personReducer from './reducers/person'
//引入 redux-thunk 用于支持异步 action
 import thunk from 'redux-thunk'
 //引入 redux 开发者工具
 import {composeWithDevTools} from 'redux-devtools-extension'

//汇总所有 reducer
const allReducer = combineReducers({
   count:countReducer,
   person:personReducer
})
//默认暴露一个 store, 注意使用 redux开发者工具的调用方式
export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))


Avatar
Aaron Fan My research interests include machine learning, signal processing, web development and robotics.