Reducer(状态更新函数)
Redux 常见问题:Reducer(状态更新函数)
如何在两个 reducer 之间共享状态?我必须使用 combineReducers 吗?
Redux 存储推荐的结构是通过键将状态对象拆分成多个“切片”或“领域”,并为每个单独的数据切片提供一个 reducer 函数来管理。这类似于标准 Flux 模式中有多个独立的 store,Redux 提供了 combineReducers 工具函数来简化这种模式的使用。然而,需要注意的是,combineReducers 并非必需 —— 它只是一个用于常见用例的辅助函数,即每个状态切片对应一个 reducer 函数,数据使用普通的 JavaScript 对象。
许多用户后来希望尝试在两个 reducer 之间共享数据,但发现 combineReducers 并不支持这样做。有几种解决方法:
- 首先,确认你是否真的需要在状态切片之间_共享_状态,还是只需要让多个切片_响应同一个 action_。后一种情况更常见,也不需要特殊处理:每个
createSlice都可以在extraReducers字段中处理其他 slice(或createAsyncThunk)生成的 action。请参阅风格指南中的让多个 reducer 响应同一个 action。 - 如果某个 reducer 需要知道另一个状态切片中的数据,可能需要调整状态树结构,让单个 reducer 负责更多数据。
- 你可能需要编写自定义函数处理其中一些 action。这可能要求用自己的顶层 reducer 函数替代
combineReducers。也可以使用 reduce-reducers 之类的工具,先让combineReducers处理大多数 action,再为跨切片的特定 action 运行更专门的 reducer。超越combineReducers展示了这种方法。 - Thunk 和 listener middleware effect 都可以通过
getState()访问完整状态。Thunk 可以从状态中读取额外数据并放进它派发的 action,使各 reducer 获得更新自身状态切片所需的信息。
总的来说,记住 reducer 只是函数 —— 你可以按任何方式组织和细分它们,推荐将它们拆分为更小的、可复用的函数(“reducer 组合”)。在拆分的过程中,如果子 reducer 需要额外数据计算下一状态,你可以从父 reducer 传入自定义的第三个参数。只需确保它们共同遵守 reducer 的基本规则:(state, action) => newState,并且以不可变方式更新状态,而不是直接修改。
进一步信息
文档
讨论
- #601: 当一个动作涉及多个 reducer 时,对 combineReducers 的担忧
- #1400: 将顶层状态对象传给分支 reducer 是一种反模式吗?
- Stack Overflow:使用 combineReducers 时如何访问状态的其他部分?
- Stack Overflow:用 redux combineReducers 简化整个子树的 reducer
- Redux Reducer 之间共享状态
我必须使用 switch 语句来处理动作吗?
不必。你可以用任何喜欢的方式让 reducer 响应 action。手写 reducer 时,switch 最常见,但使用 if 语句、函数查找表或封装这些逻辑的函数也完全可以。事实上,Redux 虽然要求 action 对象包含 type 字段,但 reducer 逻辑甚至不一定要依赖它来处理 action。
如今的标准方式是使用 createSlice,它本质上是一个查找表:reducers 字段中的每个函数处理一种 action 类型,而 slice 会替你生成对应的 action creator 和组合后的 reducer。createReducer 的 builder callback 也能为不属于 slice 的 reducer 完成同样的工作。
进一步信息
文档
讨论