设计决策
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
Redux 常见问题解答:设计决策
为什么 Redux 不将 state 和 action 传递给订阅者?
订阅者应当响应 state 值本身而非 action。state 更新是同步处理的,但订阅者通知可能被批量处理或防抖,这意味着订阅者不会在每次 action 时都被通知。这是常见的性能优化手段,可避免重复渲染。
通过 enhancer 覆盖 store.dispatch 可以批量处理或防抖订阅通知。此外,这些库能批量处理 action 以优化性能并避免重复渲染:
-
redux-batch 允许向
store.dispatch()传递 action 数组且仅触发一次通知 -
redux-batched-subscribe 可批量处理 dispatch 引发的订阅通知
Redux 确保最终会以最新 state 调用所有订阅者,但不保证每次 action 都调用每个订阅者。订阅者中可通过 store.getState() 获取 store state。若将 action 暴露给订阅者会破坏批量处理机制。
在订阅者中使用 action 的潜在场景(非官方支持)是确保组件仅在特定 action 后重渲染。正确的重渲染控制应通过:
-
shouldComponentUpdate 生命周期方法
-
React-Redux:使用 mapStateToProps 让组件仅订阅所需 store 部分
更多信息
文章
讨论
为什么 Redux 不支持使用类作为 action 和 reducer?
使用函数(action creator)返回 action 对象的设计,对习惯面向对象编程的开发者可能反直觉——他们更倾向使用类和实例。Redux 不支持类实例形式的 action 和 reducer,因为序列化/反序列化时:JSON.parse(string) 会返回普通 JS 对象而非类实例。
如 Store 常见问题所述,若不介意持久化和时间旅行调试等功能受限,可将非序列化项放入 Redux store。
序列化使浏览器能以更少内存存储所有已分发 action 和先前 store 状态。"回退"和"热重载"是 Redux 开发者体验和 DevTools 的核心功能。这也支持在服务端渲染时,将反序列化 action 存储于服务端并在浏览器重新序列化。
更多信息
文章
讨论
为什么中间件签名使用柯里化(Currying)?
Redux 中间件采用三层嵌套函数结构(形如 const middleware = storeAPI => next => action => {}),而非单层函数结构(如 const middleware = (storeAPI, next, action) => {}),这有几点原因:
首先,函数"柯里化"是函数式编程的标准技术,而 Redux 在设计上明确采用了函数式编程原则。其次,柯里化函数会创建闭包,允许在中间件生命周期内声明持久变量(可视为类实例变量的函数式等效)。最后,这仅仅是 Redux 最初设计时选择的实现方式。
有人认为声明中间件的柯里化函数签名并非必需,因为在执行 applyMiddleware 时 store 和 next 均已可用。但此问题已被确定为不值得引入破坏性变更,因为当前 Redux 生态中有数百个中间件依赖现有签名。
更多信息
讨论
为什么 applyMiddleware 使用闭包处理 dispatch?
applyMiddleware 通过闭包封装 store 原有的 dispatch 方法,创建中间件初始调用链。中间件被调用时会接收包含 getState 和 dispatch 方法的对象,这使得初始化时依赖 dispatch 的中间件能够正确运行。
更多信息
讨论
为什么 combineReducers 不将整个 state 作为第三个参数传递给每个 reducer?
combineReducers 的设计理念是鼓励按功能域拆分 reducer 逻辑。如超越 combineReducers所述,combineReducers 被刻意限定于单一常见场景:通过委托各状态切片给专属 reducer 来更新普通 JavaScript 对象状态树。
若添加第三个参数(整个状态树/回调函数/其他状态片段等)会引发歧义。如果 combineReducers 不能满足你的需求,当需要深度嵌套的 reducer 或需访问全局状态时,可考虑使用替代方案如 combineSectionReducers 或 reduceReducers。
如果现有工具都无法满足您的需求,您完全可以自行编写一个完全符合需求的函数。
扩展阅读
文章
讨论
为何不允许在 mapDispatchToProps 中使用 getState() 或 mapStateToProps() 的返回值?
存在这样的需求:希望在 mapDispatch 内部使用整个 state 或 mapState 的返回值,这样在 mapDispatch 中声明的函数就能访问存储中的最新返回值。
mapDispatch 不支持此方法,因为这将导致每次存储更新时都要调用 mapDispatch。会造成每次状态更新都重新创建函数,从而带来严重的性能开销。
处理此场景的首选方案(需要基于当前状态和 mapDispatchToProps 函数调整属性)是通过 connect 函数的第三个参数 mergeProps 实现。如果指定该参数,它会接收 mapStateToProps()、mapDispatchToProps() 和容器组件属性的结果。mergeProps 返回的普通对象将作为属性传递给被包装组件。
扩展阅读
讨论