Redux 的使用
1 简介
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。
2 三大原则
- 单一数据源 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。
- State 是只读的(可预测性) 唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象(state + action = new state)。
- 使用纯函数来执行修改 为了描述 action 如何改变 state tree ,你需要编写 reducers。输入相同,输出一定相同。
3 基础
3.1 Action
Action 是把数据从应用(译者注:这里之所以不叫 view 是因为这些数据有可能是服务器响应,用户输入或其它非 view 的数据 )传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。Action 本质上是 JavaScript 普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。多数情况下,type 会被定义成字符串常量。当应用规模越来越大时,建议使用单独的模块或文件来存放 action。
|
|
3.2 Reducer
Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
3.3 Store
- getState() : 返回应用当前的 state 树。
- dispatch(action) : 分发 action。这是触发 state 变化的惟一途径。
- subscribe(listener) : 添加一个变化监听器。每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。
3.4 API
3.4.1 createStore(reducer, [preloadedState], enhancer)
创建一个 Redux store 来以存放应用中所有的 state。应用中应有且仅有一个 store。
3.4.2 combineReducers(reducers)
随着应用变得越来越复杂,可以考虑将 reducer 函数 拆分成多个单独的函数,拆分后的每个函数负责独立管理 state 的一部分。combineReducers 辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数,然后就可以对这个 reducer 调用 createStore 方法。
3.4.3 bindActionCreators(actionCreators, dispatch)
把一个 value 为不同 action creator 的对象,转成拥有同名 key 的对象。同时使用 dispatch 对每个 action creator 进行包装,以便可以直接调用它们。
3.5 react-redux API
3.5.1 <Provider store>
<Provider store>
使组件层级中的 connect() 方法都能够获得 Redux store。
3.5.2 connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
- 连接 React 组件与 Redux store。
- mapStateToProps(state, [ownProps]): stateProps: 如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并。如果你省略了这个参数,你的组件将不会监听 Redux store。
- [mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): 如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator,对象所定义的方法名将作为属性名;每个方法将返回一个新的函数,函数中 dispatch 方法会将 action creator 的返回值作为参数执行。这些属性会被合并到组件的 props 中。
4 扩展
4.1 不可变数据
4.1.1 为什么需要不可变数据
- 性能优化(引用比较)
- 易于调试和跟踪(计算 diff 值)
- 易于推测
4.1.2 如何操作不可变数据
-
原生写法
1 2 3 4 5 6 7 8
//性能最高 const state = { filter: "completed", todos: ["Learn React"] }; const newState = { ...state, todos: [...state.todos, "Learn Redux"] }; const newState2 = Object.assign({}, state, { todos: [...state.todos, "Learn Redux"] });
-
immutability-helper
1 2 3 4 5 6
//深层次的不可变数据方便 import update from 'immutability-helper'; const state = {filter : "completed", todos: ["Learn React"]}; const newState = update(state, { todos: {$push: ["Learn Redux"]});
-
immer
1 2 3 4 5 6 7 8
//可读性强,性能层次较深的话会较低 import produce from "immer"; const state = { filter: "completed", todos: ["Learn React"] }; const newState = produce(state, drafState => { drafState.todos.push("Learn Redux"); });