Redux和React-redux小结

最近学习了 Redux 和 React-redux,摘录和总结一下。

Redux

action

强制使用 action 来描述所有变化带来的好处是可以清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。action 就像是描述发生了什么的指示器。最终,为了把 action 和 state 串起来,开发一些函数,这就是 reducerreducer 只是一个接收 state 和 action,并返回新的 state 的函数

Action 就是一个普通 JavaScript 对象(注意到没,这儿没有任何魔法?)用来描述发生了什么。

对于小应用来说,使用字符串做 action type 更方便些。不过,在大型应用中把它们显式地定义成常量还是利大于弊的。

记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。

开发复杂的应用时,不可避免会有一些数据相互引用。建议你尽可能地把 state 范式化,不存在嵌套。把所有数据放到一个对象里,每个数据以 ID 为主键,不同实体或列表间通过 ID 相互引用数据。把应用的 state 想像成数据库。这种方法在 normalizr 文档里有详细阐述。例如,实际开发中,在 state 里同时存放 todosById: { id -> todo } 和 todos: array 是比较好的方式,本文中为了保持示例简单没有这样处理。

reducer

永远不要在 reducer 里做这些操作:

  • 修改传入参数;
  • 执行有副作用的操作,如 API 请求和路由跳转;
  • 调用非纯函数,如 Date.now() 或 Math.random()。

纯函数:函数的返回结果只依赖于它的参数。

函数执行过程里面没有副作用。

注意: 不要修改 state。 使用 Object.assign() 新建了一个副本。不能这样使用 Object.assign(state, { visibilityFilter: action.filter }),因为它会改变第一个参数的值。你必须把第一个参数设置为空对象。你也可以开启对 ES7 提案对象展开运算符的支持, 从而使用 { …state, …newState } 达到相同的目的。

在 default 情况下返回旧的 state。遇到未知的 action 时,一定要返回旧的 state。

我们需要修改数组中指定的数据项而又不希望导致突变, 因此我们的做法是在创建一个新的数组后, 将那些无需修改的项原封不动移入, 接着对需修改的项用新生成的对象替换。(译者注:Javascript 中的对象存储时均是由值和指向值的引用两个部分构成。此处突变指直接修改引用所指向的值, 而引用本身保持不变。) 最后,时刻谨记永远不要在克隆 state 前修改它。

关于 reducer 合成,它是开发 Redux 应用最基础的模式,使用combineReducers()

store

Store 就是把它们联系到一起的对象。Store 有以下职责:

  1. 维持应用的 state;
  2. 提供 getState() 方法获取 state;
  3. 提供 dispatch(action) 方法更新 state;
  4. 通过 subscribe(listener) 注册监听器;
  5. 通过 subscribe(listener) 返回的函数注销监听器。

数据流

Redux 应用中数据的生命周期遵循下面 4 个步骤:

  1. 调用 store.dispatch(action)。
  2. Redux store 调用传入的 reducer 函数(Store 会把两个参数传入 reducer:当前的state树和action)
  3. 根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。
  4. Redux store 保存了根 reducer 返回的完整 state 树(所有订阅 store.subscribe(listener) 的监听器都将被调用;监听器里可以调用 store.getState()获得当前 state)

注意 reducer 是纯函数。它仅仅用于计算下一个 state。它应该是完全可预测的:多次传入相同的输入必须产生相同的输出。它不应做有副作用的操作,如 API 调用或路由跳转。这些应该在 dispatch action 前发生。

react-redux

connect

connect 有 4 个参数,常用的有前两个,mapStateToProps 和 mapDispatchToProps,前者用于从 store 获取状态 更新 UI 视图,后者用于事件发送到 store

mapStateToProps

mapDispatchToProps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import React from 'react';
import { connect } from 'react-redux';
import { getString } from '../../../utils/i18n';
const mapStateToProps = (state, ownProps) => {
const appState = state.currentState.appState;
return {
className: styleByState(appState, ownProps.operationType),
};
};
const styleByState = (state, operationType) => {
switch (operationType) {
case 'train':
case 'predict':
case 'stop':
default:
return null;
}
};
const mapDispatchToProps = (dispatch, ownProps) => {
return {
clickBtn: () => {
if (ownProps.operationType == 'predict') {
clickPredict = true;
}
dispatch(ownProps.action);
},
};
};
export const ActionButtonBasic = ({
clickBtn,
operationType,
trainState,
className,
}) => {
return (
<div
className={`action-button ${operationType} ${trainState} ${className}`}
onClick={clickBtn}
>
<div className="action-icon" />
<div className="action-text">{getString(operationType)}</div>
</div>
);
};
export const ActionButton = connect(
mapStateToProps,
mapDispatchToProps
)(ActionButtonBasic);
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2018-2020 Jee
  • Visitors: | Views:

如果您觉得此文章帮助到了您,请作者喝杯咖啡吧~

支付宝
微信