Skip to main content

状态组织

Redux FAQ:状态组织​

我必须把所有状态都放到 Redux 里吗?我是否应该使用 React 的 useState 或 useReducer?​

对此没有“正确”的答案。有些用户喜欢将每一条数据都放入 Redux,以始终维护一个完全序列化且可控的应用状态。另一些人则倾向于将非关键性或 UI 状态(如“这个下拉菜单当前是否打开”)保存在组件的内部状态中。

使用本地组件状态是可以的。作为开发者,确定应用由哪些状态组成,以及每条状态应该放在哪里,是 你的 工作。找到适合你的平衡点,然后坚持下去。

判断何种数据应放入 Redux 的一些常见经验法则:

  • 应用的其他部分是否关心这些数据?
  • 是否需要基于该原始数据创建进一步的派生数据?
  • 这些相同数据是否驱动多个组件?
  • 是否希望能够将该状态恢复到某个时间点(即时间旅行调试)?
  • 是否希望缓存数据(即,如果状态中已有数据,则不重新请求)?
  • 是否希望在热重载 UI 组件时保持数据一致(热重载可能会丢失组件内部状态)?

更多信息​

相关文章

讨论

我能把函数、Promise 或其他不可序列化的项放进 store 状态吗?​

强烈建议你只往 store 里放普通的可序列化对象、数组和基本类型。_技术上_可以往 store 中插入不可序列化的项,但这样做会破坏持久化和重载 store 内容的能力,还会影响时间旅行调试。

如果你可以接受持久化和时间旅行调试可能无法正常工作,那么完全可以将不可序列化的项放入 Redux store。毕竟,这是 你的 应用,如何实现由你决定。和 Redux 相关的其他许多事情一样,只要你理解所涉及的权衡即可。

更多信息​

讨论

我如何组织状态中的嵌套或重复数据?​

带 ID、嵌套结构或对象关系的数据通常应采用“归一化”方式存储:每个对象只保存一次,并以 ID 为键;引用该对象的其他对象只保存 ID,而不是复制整个对象。可以把 store 的一部分想象成数据库,每种条目各有一张“表”。

大多数应用可以使用 Redux Toolkit 的 createEntityAdapter 在 slice 中管理归一化集合。它采用 { ids, entities } 状态结构,并提供添加、更新和删除条目的 reducer 函数及读取条目的 selector。

该 adapter 不会自动把嵌套对象转换为独立实体,也不会把对象关系替换成 ID。如果 API 返回的是嵌套数据,应先将其转换为归一化结构,再加入 store。有关这一过程及 Normalizr 等工具,请参阅归一化嵌套数据。

更多信息​

文档

相关文章

讨论

我应该把表单状态或其他 UI 状态放入 store 吗?​

决定什么状态放 Redux 的经验法则 同样适用于此问题。

基于这些经验法则,大多数表单状态无需放入 Redux,因为它们大概率不会被多个组件共享。但具体情况依然取决于你和你的应用。你可能会把一些表单状态放入 Redux,因为你正在编辑最初来自 store 的数据,或者确实需要在应用其他组件中看到正在编辑的值。另一方面,保持表单状态在组件内部(本地状态)更简单,用户完成操作后再派发 action 把数据放到 store。

基于此,在大多数情况下,其实不需要基于 Redux 的表单管理库。我们建议按以下顺序尝试:

  • 即使数据来自 Redux store,也可以先用 useState 手动编写表单逻辑;很可能这就足够了。有关 React 表单的优秀指导,请参阅 Gosha Arinich 关于 React 表单的文章。
  • 如果觉得手动编写表单过于困难,可以试试 React Hook Form 或 TanStack Form 等 React 表单库。它们将表单状态保存在组件中,并提供验证和提交处理。用户提交时,再派发一个 action(或调用 RTK Query mutation)提交最终值。
  • Redux-Form 和 React-Redux-Form 等基于 Redux 的表单库已不再积极维护,我们不建议新项目使用。如果确实需要在用户输入时将表单值保存在 store 中,可以为表单编写一个小型 slice,并在组件的 change handler 中更新它。

如果你决定把表单状态放到 Redux,需要考虑性能问题。每次文本输入的击键都派发 action 通常不值得,或许可以考虑用缓冲击键的方式让更改保持本地,然后再派发。一如既往,花些时间分析你应用的整体性能需求。

其他类型的 UI 状态也遵循这些经验法则。典型例子是跟踪 isDropdownOpen 标志。在大多数情况下,应用其他部分不关心这个,所以应该保留在组件状态。但视你的应用情况,也可能合理通过 Redux 来管理弹窗及其他弹出层、标签页、展开面板等。

更多信息​

文档

相关文章