状态组织
Redux FAQ:状态组织
我必须把所有状态都放到 Redux 里吗?我是否应该使用 React 的 useState 或 useReducer?
对此没有“正确”的答案。有些用户喜欢将每一条数据都放入 Redux,以始终维护一个完全序列化且可控的应用状态。另一些人则倾向于将非关键性或 UI 状态(如“这个下拉菜单当前是否打开”)保存在组件的内部状态中。
使用本地组件状态是可以的。作为开发者,确定应用由哪些状态组成,以及每条状态应该放在哪里,是 你的 工作。找到适合你的平衡点,然后坚持下去。
判断何种数据应放入 Redux 的一些常见经验法则:
- 应用的其他部分是否关心这些数据?
- 是否需要基于该原始数据创建进一步的派生数据?
- 这些相同数据是否驱动多个组件?
- 是否希望能够将该状态恢复到某个时间点(即时间旅行调试)?
- 是否希望缓存数据(即,如果状态中已有数据,则不重新请求)?
- 是否希望在热重载 UI 组件时保持数据一致(热重载可能会丢失组件内部状态)?
更多信息
相关文章
讨论
我能把函数、Promise 或其他不可序列化的项放进 store 状态吗?
强烈建议你只往 store 里放普通的可序列化对象、数组和基本类型。_技术上_可以往 store 中插入不可序列化的项,但这样做会破坏持久化和重载 store 内容的能力,还会影响时间旅行调试。
如果你可以接受持久化和时间旅行调试可能无法正常工作,那么完全可以将不可序列化的项放入 Redux store。毕竟,这是 你的 应用,如何实现由你决定。和 Redux 相关的其他许多事情一样,只要你理解所涉及的权衡即可。
更多信息
讨论
- #1248:在 reducer 中存储 React 组件可以吗?
- #1279:Flux 中放置 Map 组件的建议?
- #1390:组件加载
- #1407:分享一个很棒的基类
- #1793:Redux 状态中的 React 元素
我如何组织状态中的嵌套或重复数据?
带有 ID、嵌套或关系的数据通常应以“规范化”的方式存储:每个对象只存储一次,以 ID 作为键,其他引用该对象的地方只存储其 ID,而不是整个对象的副本。将 store 的部分内容视为数据库,按类型划分“表”会有所帮助。像 normalizr 和 redux-orm 这样的库,可以帮你管理规范化数据,并提供抽象。
更多信息
文档
- Redux 精要:规范化数据
- Redux 基础:异步逻辑和数据流
- Redux 基础:标准 Redux 模式
- 示例:真实世界示例
- 使用 Redux:结构化 Reducers - 先决概念
- 使用 Redux:结构化 Reducers - 规范化状态形状
相关文章
讨论
- #316:如何创建嵌套 reducers?
- #815:处理数据结构
- #946:拆分 reducers 时如何更新相关状态字段?
- #994:更新嵌套实体时如何减少样板代码?
- #1255:React/Redux 中使用 Normalizr 处理嵌套对象
- #1824:规范化状态与垃圾回收
- Twitter:状态结构应规范化
- Stack Overflow:Redux reducers 中如何处理树形实体?
我应该把表单状态或其他 UI 状态放入 store 吗?
决定什么状态放 Redux 的经验法则 同样适用于此问题。
基于这些经验法则,大多数表单状态无需放入 Redux,因为它们大概率不会被多个组件共享。但具体情况依然取决于你和你的应用。你可能会把一些表单状态放入 Redux,因为你正在编辑最初来自 store 的数据,或者确实需要在应用其他组件中看到正在编辑的值。另一方面,保持表单状态在组件内部(本地状态)更简单,用户完成操作后再派发 action 把数据放到 store。
基于此,在大多数情况下,其实不需要基于 Redux 的表单管理库。我们建议按以下顺序尝试:
- 即使数据来自 Redux store,也先手写表单逻辑。通常这就够用了。(参考 Gosha Arinich 关于在 React 中处理表单的文章)
- 如果觉得手写表单太难,试试 React 表单库,比如 Formik 或 React-Final-Form。
- 如果完全确定必须使用 Redux 表单库(因为其他方法不够用),再考虑 Redux-Form 和 React-Redux-Form。
如果你决定把表单状态放到 Redux,需要考虑性能问题。每次文本输入的击键都派发 action 通常不值得,或许可以考虑用缓冲击键的方式让更改保持本地,然后再派发。一如既往,花些时间分析你应用的整体性能需求。
其他类型的 UI 状态也遵循这些经验法则。典型例子是跟踪 isDropdownOpen 标志。在大多数情况下,应用其他部分不关心这个,所以应该保留在组件状态。但视你的应用情况,也可能合理通过 Redux 来管理弹窗及其他弹出层、标签页、展开面板等。
更多信息
相关文章