企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 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]; } }) ```