# Reducer
reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。
```js
(previousState, action) => newState
```
可以理解为旧状态向新状态的一个映射,其中action就是改变这个状态的方法。
`previousState --(action)--> newState`
## 处理 Reducer 关系时的注意事项
开发复杂的应用时,不可避免会有一些数据相互引用。建议你尽可能地把 state 范式化,不存在嵌套。把所有数据放到一个对象里,每个数据以 ID 为主键,不同实体或列表间通过 ID 相互引用数据。把应用的 state 想像成数据库。这种方法在 normalizr 文档里有详细阐述。例如,实际开发中,在 state 里同时存放 `todosById: { id -> todo }` 和 `todos: array<id>` 是比较好的方式。
## Reducer 的纯净性
之所以称作 reducer 是因为它将被传递给 `Array.prototype.reduce(reducer, ?initialValue)` 方法。保持 reducer 纯净非常重要。永远不要在 reducer 里做这些操作:
- 修改传入参数;
- 执行有副作用的操作,如 API 请求和路由跳转;
- 调用非纯函数,如 Date.now() 或 Math.random()。
所谓纯净性,就是只要传入参数相同,返回计算得到的下一个 state 就一定相同。没有特殊情况、没有副作用,没有 API 请求、没有变量修改,单纯执行计算。
## Action 的处理
一个约定俗成的做法是,actions 拥有一个常量 type 帮助 reducer (或 Flux 中的 Stores ) 识别它们。我们建议你使用 string 而不是 Symbols 作为 action type ,因为 string 是可序列化的,而使用 Symbols 会毫无必要地使记录和重演变得困难。
有以下一个 Reducer :
```js
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
default:
return state
}
}
```
在使用action的时候需要注意:
1. 不要修改 state。 使用 Object.assign() 新建了一个副本。不能这样使用 Object.assign(state, { visibilityFilter: action.filter }),因为它会改变第一个参数的值。你必须把第一个参数设置为空对象。你也可以开启对ES7提案对象展开运算符的支持, 从而使用 { ...state, ...newState } 达到相同的目的。
2. 在 default 情况下返回旧的 state。遇到未知的 action 时,一定要返回旧的 state。
### Object.assign 须知
Object.assign() 是 ES6 特性,但多数浏览器并不支持。你要么使用 polyfill,Babel 插件,或者使用其它库如 _.assign() 提供的帮助方法。
### switch 和样板代码须知
switch 语句并不是严格意义上的样板代码。Flux 中真实的样板代码是概念性的:更新必须要发送、Store 必须要注册到 Dispatcher、Store 必须是对象(开发同构应用时变得非常复杂)。为了解决这些问题,Redux 放弃了 event emitters(事件发送器),转而使用纯 reducer。
很不幸到现在为止,还有很多人存在一个误区:根据文档中是否使用 switch 来决定是否使用它。如果你不喜欢 switch,完全可以自定义一个 createReducer 函数来接收一个事件处理函数列表。
### action type 的命名规范
在 Flux 中,传统的想法是将每个 action type 定义为 string 常量:
```js
const ADD_TODO = 'ADD_TODO';
const REMOVE_TODO = 'REMOVE_TODO';
const LOAD_ARTICLE = 'LOAD_ARTICLE';
```
这么做的优势?人们通常声称常量不是必要的。对于小项目也许正确。 对于大的项目,将 action types 定义为常量有如下好处:
帮助维护命名一致性,因为所有的 action type 汇总在同一位置。
有时,在开发一个新功能之前你想看到所有现存的 actions 。而你的团队里可能已经有人添加了你所需要的action,而你并不知道。
Action types 列表在 Pull Request 中能查到所有添加,删除,修改的记录。这能帮助团队中的所有人及时追踪新功能的范围与实现。
如果你在导入一个 Action 常量的时候拼写错误,你会得到 undefined 。当你纳闷 action 被分发出去而什么也没发生的时候,一个拼写错误更容易被发现。
你的项目的约定取决与你自己。开始时,可能用的是 inline string,之后转为常量,也许之后将他们归为一个独立文件。Redux 不会给予任何建议,选择你自己最喜欢的。
#### 常量表示的 Reducers
使用以上命名规则的 action,可以使用常量表示法直接生成 Reducers
```js
export const todos = createReducer([], {
[ADD_TODO](state, action) {
let text = action.text.trim();
return [...state, text];
}
})
```
- 简介
- 第一章 React入门
- 1.1 创建一个React项目
- 1.2 组件
- 1.3 JSX
- 1.4 eject
- 1.5 渲染
- 第二章 React组件
- 2.1 组件定义
- 2.2 数据处理
- 2.2.1 props
- 2.2.2 state
- 2.3 生命周期
- 2.3.1 装载过程
- 2.3.2 更新过程
- 2.3.3 卸载过程
- 2.4 事件处理
- 2.5 条件渲染
- 2.6 列表渲染
- 第三章 React高级
- 3.1 静态类型检查
- 3.1.1 flow
- 3.1.2 typescript
- 3.2 React Developer Tools
- 第四章 Redux状态管理
- 4.1 安装与配置
- 4.2 一个简单的计数器开始
- 4.3 Store
- 4.3.1 获取state
- 4.3.2 subscribe
- 4.4 Action
- 4.4.1 Action Creators
- 4.5 Reducer
- 4.5.1 Reducer 的拆分
- 4.6 与其他状态管理工具的对比
- 第五章 React-Router路由
- 参考资料