Redux 常见问答:组织 State
组织 State
必须将所有的 state 都放入 Redux 吗?应该使用 React 的 setState() 吗?
对此没有“绝对正确”的答案。一些用户喜欢将每一条数据都保存在 Redux 中,以始终维护其应用程序的完全可序列化和受控的版本。其他人更喜欢在组件的内部 state 中保留非关键的或 UI state,例如“此下拉列表当前是否打开”。
使用本地组件 state 是 OK 的。作为开发人员,由你自己决定构成应用程序的 state 类型以及每个 state 应该存在的位置。找到一个适合你的平衡点,并坚持下去。
下面是应该将哪些数据放入 Redux 的一些常见经验法则:
- 应用程序的其他部分是否关心这些数据?
- 你是否需要基于这些原始数据创建进一步的派生数据?
- 是否使用相同的数据来驱动多个组件?
- 将此 state 恢复到给定的时间点(即时间旅行调试)对你有价值吗?
- 你是否要缓存数据(即,如果它已经存在,则使用 state 中的内容而不是重新请求它)?
- 在热重载 UI 组件(交换时可能会丢失其内部 state)时,你需要保持这些数据一致吗?
有许多社区包实现了在 Redux store 中存储每个组件 state 的各种方法,例如 redux-component、redux-react-local 等。也可以按照 this.setState( (previousState) => reducer(previousState, someAction))
的方式将 Redux 的原理和 reducer 概念应用于更新本地组件 state 的任务中。
更多信息
文献
- 何时(何时不)使用 Redux
- 使用 React 和 Redux 找到 state 的位置
- 一个 setState 的案例
- 如何在 React 中处理 state:缺失的常见问答
- 在哪里保存 React 组件数据:state、store、static 和 this
- React 应用程序 State 的 5 种类型
- 像数据库一样塑造 Redux Store
讨论
- #159:研究使用 Redux 来处理伪本地(pseudo-local)组件 state
- #1098:在可重用的 React 组件中使用 Redux
- #1287:如何在 Redux 的 store 和 React 的 state 之间进行选择?
- #1385:将所有 state 存储在一个不可变原子中的缺点是什么?
- Twitter:应该将某些值存放在 React 组件的 state 里吗?
- Twitter:使用 reducer 更新组件
- React 论坛:Redux 和全局 state vs 本地 state
- Reddit:“我什么时候应该在 Redux store 里放东西?”
- Stack Overflow:为什么 state(甚至不是全局的 state)都集中在一个地方?
- Stack Overflow:所有组件 state 都应该保存在 Redux store 中吗?
相关库
可以将函数、promises 或其他不可序列化的项放入 store state 吗?
强烈建议你只将普通的可序列化对象、数组和原始类型放入 store 中。虽然 技术上 可以将不可序列化的项插入到 store 中,但这样做会破坏 store 内容的持久化和再水化能力,并影响时间旅行调试。
如果你不在意持久性和时间旅行调试等可能无法按预期进行,那么完全可以将不可序列化的项放入 Redux store 中。当然,它是 你的 应用程序,你有最终的决定权。与有关 Redux 的许多其他事情一样,请确保你了解所涉及的权衡利弊。
更多信息
讨论
- #1248:是否可以将 react 组件存储在 reducer 中?
- #1279:对于在 Flux 中把 Map 组件放在哪里有什么建议吗?
- #1390:组件加载
- #1407:分享一个很棒的基类
- #1793:Redux State 下 React 的元素
如何组织 state 中的嵌套或重复数据?
具有 ID、嵌套结构或关系型的数据,通常应以“归一化”方式存储:每个对象应以 ID 为键仅存储一次,其他引用它的对象应仅存储 ID,而不是整个对象的副本。将 store 的某些部分看作数据库,每项类型都有单独的“表”,这样可能可以帮助理解。Normalizr 和 redux-orm 等,这些库可以在管理归一化数据上提供帮助和抽象能力。
更多信息
文档
- Redux 深入浅出:异步逻辑和数据流
- Redux 深入浅出:标准 Redux 模式
- 示例:真实示例
- Redux 使用指南:结构化 Reducers——预置知识
- Redux 使用指南:结构化 Reducers——State 归一化
- 示例:Tree View
文献
讨论
- #316:如何创建嵌套 reducers?
- #815:使用数据结构
- #946:使用拆分 reducers 以更新相关 state 字段的最佳方法是什么?
- #994:更新嵌套对象时如何削减样板代码?
- #1255: Normalizr 在 React/Redux 中与嵌套对象一起使用
- #1269:添加树视图示例
- #1824:归一化 state 和垃圾回收
- Twitter:state 结构应该归一化
- Stack Overflow:如何处理 Redux reducer 中的树形实体?
- Stack Overflow:如何优化嵌套组件里 props 的很小改动?
应该将表单 state 或其他 UI state 放在 store 中吗?
决定把什么放入 Redux store 的经验法则同样也适用于这个问题。
根据这些经验法则,大多数表单 state 不需要放入 Redux,因为它一般不需要在组件之间共享。但是,最终取决于你和你的应用程序。你可能会选择在 Redux 中保留某些表单 state,因为你需要修改最初来自 store 的数据,或者你需要查看显示在应用程序其他组件中的正在处理的数据。另一方面,将表单 state 保存在组件本地可能要简单得多,并在用户完成表单后才 dispatch action 来将数据放入 store 中。
基于此,在大多数情况下,你可能也不需要基于 Redux 的表单管理库。我们建议你按以下顺序尝试这些方法:
- 即使数据来自 Redux store,也请先手动编写表单逻辑。很肯能这就是你想要的。(请参阅 Gosha Arinich 关于在 React 中使用表单的帖子来获得一些好的指导。)
- 如果你认为“手动”编写表单太难,请尝试使用基于 React 的表单库,例如 Formik 或 React-Final-Form。
- 如果你确信你必须使用基于 Redux 的表单库,因为其他办法还不能满足,那么你可以看看 Redux-Form 和 React-Redux-Form。
如果你在 Redux 中保存表单 state,你应该花一些时间来考虑性能。对文本框的每次输入变化 dispatch action 也许是没有必要的,你可能需要研究在 dispatch 前缓存输入变化以保存本地更改的方法。与往常一样,你需要花一些时间来分析应用程序的整体性能需求。
其他类型的 UI state 也遵循这些经验法则。经典示例是追踪 isDropdownOpen
标志。在大多数情况下,应用程序的其余部分并不关心它,因此它应该保存在组件 state 里。但是,根据应用程序的实际情况,使用 Redux 来管理对话框和其他弹出窗口、选项卡、扩展面板等是有意义的。
更多信息
文献