异步 Action
通过 redux-thunk
,在 action 中 dispatch action ,可以是简化异步工作流。
Middleware
它提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。 middleware 最优秀的特性就是可以被链式组合。你可以在一个项目中使用多个独立的第三方 middleware。
注意 applyMiddleware 的实现方式。
// 警告:这只是一种“单纯”的实现方式!
// 这 *并不是* Redux 的 API.
function applyMiddleware(store, middlewares) {
middlewares = middlewares.slice()
middlewares.reverse()
let dispatch = store.dispatch
middlewares.forEach(middleware =>
dispatch = middleware(store)(dispatch)
)
return Object.assign({}, store, { dispatch })
}
计算衍生数据
Reselect 库可以创建可记忆的(Memoized)、可组合的 selector 函数。Reselect selectors 可以用来高效地计算 Redux store 里的衍生数据。
实现撤销历史
reducer enhance 的产生
combineReducer
- 在生成新的 state 树时,combinerReducers 将调用每一个拆分之后的 reducer 和与当前的 Action,如果有需要的话会使得每一个 reducer 有机会响应和更新拆分后的 state。所以,在这个意义上, combineReducers 会调用所有的 reducer,严格来说是它包装的所有 reducer。
- 你可以在任何级别的 reducer 中使用 combineReducer,不仅仅是在创建根 reducer 的时候。
State 范式化(重要)
在 Redux Store 中管理关系数据或嵌套数据的推荐做法是将这一部分视为数据库,并且将数据按范式化存储。因为:
- 当数据在多处冗余后,需要更新时,很难保证所有的数据都进行更新。
- 嵌套的数据意味着 reducer 逻辑嵌套更多、复杂度更高。尤其是在打算更新深层嵌套数据时。
- 不可变的数据在更新时需要状态树的祖先数据进行复制和更新,并且新的对象引用会导致与之 connect 的所有 UI 组件都重复 render。尽管要显示的数据没有发生任何改变,对深层嵌套的数据对象进行更新也会强制完全无关的 UI 组件重复 render
如何设计范式数据:
- 任何类型的数据在 state 中都有自己的 “表”。
- 任何 “数据表” 应将各个项目存储在对象中,其中每个项目的 ID 作为 key,项目本身作为 value。
- 任何对单个项目的引用都应该根据存储项目的 ID 来完成。
- ID 数组应该用于排序。
Reducer 逻辑复用
高阶 reducer 是一个接收 reducer 函数作为参数,并返回新的 reducer 函数的函数。它也可以被看作成一个“reducer 工厂”。
创建特定的 reducer 有两种最常见的方式,一个是使用给定的前缀或者后缀生成新的 action 常量,另一个是在 action 对象上附加额外的信息。下面是它们大概的样子:
不可变更新模式
- 更新嵌套的对象
- 在数组中插入和删除数据
- 在一个数组中更新一个项目
- 不可变更新工具库
初始化 State
他们会优先选择通过 preloadedState 参数传到 createStore() 的对象中的相应值,但是如果你不传任何东西,或者没设置相应的字段,那么 reducer 就会选择指定的默认 state 参数来取代。