Reducer 和 combineReducers
Reducer 是 (state, action) => newState 的纯函数;combineReducers 把多个「子 reducer」合成一棵状态树,且按 key 隔离各 slice。
源码:packages/redux/src/combineReducers.ts、types/reducers.ts。
1. Reducer 规则
| 必须 | 禁止 |
|---|---|
| 同步、纯函数 | API 请求、随机数、Date.now |
| 不修改入参 state | 直接 state.x = 1 |
| 未知 action 时返回原 state 或等价引用 | 默认 undefined 导致整树重置(仅初始化例外) |
初始化:传入 preloadedState 或 dispatch @@INIT 得到初始树。
2. combineReducers 做什么
输入:{ user: userReducer, posts: postsReducer }
输出:一个根 reducer,行为:
- 对每个 key 调用对应子 reducer,传入 该 key 当前 slice 和 同一个 action。
- 组装新对象
{ user: nextUser, posts: nextPosts }。 - 若所有 slice 引用未变,根 reducer 可返回原根对象(引用相等优化)。
重要:子 reducer 看不到 其它 slice 的 state(见 08 §四)。
3. action 如何影响多 slice
- 全局 action(如
LOGOUT):每个子 reducer 都可处理,常把各自 slice 置初始态。 - 局部 action(如
posts/ADD):多数 reducer 走 default 返回原引用,仅相关 slice 变化。
命名空间习惯:sliceName/actionName(RTK 自动生成)。
4. 常见误区
| 误区 | 后果 |
|---|---|
| 在 reducer 里深拷贝整树 | 性能差;应只改相关 slice |
slice 返回 undefined | 该 key 被清空(非 INIT 时常是 bug) |
| 用 combineReducers 做「派生全局状态」 | 应放 selector 或 middleware |
5. 与 RTK 的关系
@reduxjs/toolkit 的 createSlice 生成 reducer + action creators,语义仍符合 上述规则;学习 Redux core 仍须理解 combineReducers。
6. 总结
- 一个 action → 所有 reducer 各算一遍 slice。
- 树形 state 来自 key 分区,不是 reducer 里手动拆。
- 纯 + 引用稳定 决定订阅方能否少渲染(配合 react-redux 的浅比较)。