Skip to main content

Redux 常见问题解答:组织状态

¥Redux FAQ: Organizing State

目录

¥Table of Contents

组织状态

¥Organizing State

我必须将所有状态放入 Redux 中吗?我应该使用 React 的 useState 还是 useReducer

¥Do I have to put all my state into Redux? Should I ever use React's useState or useReducer?

对此没有“正确”的答案。一些用户更喜欢将每一条数据保留在 Redux 中,以便始终维护其应用的完全可序列化和受控版本。其他人更喜欢在组件的内部状态中保留非关键或 UI 状态,例如“此下拉列表当前是否打开”。

¥There is no “right” answer for this. Some users prefer to keep every single piece of data in Redux, to maintain a fully serializable and controlled version of their application at all times. Others prefer to keep non-critical or UI state, such as “is this dropdown currently open”, inside a component's internal state.

使用本地组件状态就可以了。作为开发者,你的工作是确定应用由哪些类型的状态组成,以及每个状态应该位于何处。找到一个适合你的平衡点,然后顺其自然。

¥Using local component state is fine. As a developer, it is your job to determine what kinds of state make up your application, and where each piece of state should live. Find a balance that works for you, and go with it.

用于确定应将哪种数据放入 Redux 的一些常见经验规则:

¥Some common rules of thumb for determining what kind of data should be put into Redux:

  • 应用的其他部分是否关心这些数据?

    ¥Do other parts of the application care about this data?

  • 你是否需要能够基于此原始数据创建进一步的派生数据?

    ¥Do you need to be able to create further derived data based on this original data?

  • 是否使用相同的数据来驱动多个组件?

    ¥Is the same data being used to drive multiple components?

  • 能够将此状态恢复到给定时间点(即时间旅行调试)对你有价值吗?

    ¥Is there value to you in being able to restore this state to a given point in time (ie, time travel debugging)?

  • 你是否想要缓存数据(即,如果状态已经存在,则使用状态而不是重新请求它)?

    ¥Do you want to cache the data (ie, use what's in state if it's already there instead of re-requesting it)?

  • 你是否希望在热重载 UI 组件时保持这些数据一致(交换时可能会丢失其内部状态)?

    ¥Do you want to keep this data consistent while hot-reloading UI components (which may lose their internal state when swapped)?

更多信息

¥Further information

文章

¥Articles

讨论

¥Discussions

我可以将函数、promise 或其他不可序列化的项目放入我的存储状态中吗?

¥Can I put functions, promises, or other non-serializable items in my store state?

强烈建议你只将普通的可序列化对象、数组和基元放入存储中。从技术上讲,可以将不可序列化的项目插入到存储中,但这样做可能会破坏存储内容的持久性和重新水化的能力,并且会干扰时间旅行调试。

¥It is highly recommended that you only put plain serializable objects, arrays, and primitives into your store. It's technically possible to insert non-serializable items into the store, but doing so can break the ability to persist and rehydrate the contents of a store, as well as interfere with time-travel debugging.

如果你对持久性和时间旅行调试等可能无法按预期工作的事情感到满意,那么完全欢迎你将不可序列化的项目放入 Redux 存储中。最终,这是你的应用,如何实现它取决于你。与 Redux 的许多其他事情一样,只要确保你了解其中涉及的权衡即可。

¥If you are okay with things like persistence and time-travel debugging potentially not working as intended, then you are totally welcome to put non-serializable items into your Redux store. Ultimately, it's your application, and how you implement it is up to you. As with many other things about Redux, just be sure you understand what tradeoffs are involved.

更多信息

¥Further information

讨论

¥Discussions

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

¥How do I organize nested or duplicate data in my state?

具有 ID、嵌套或关系的数据通常应以“规范化”方式存储:每个对象都应该存储一次,并以 ID 为键,引用它的其他对象应该只存储 ID,而不是整个对象的副本。将存储的某些部分视为数据库可能会有所帮助,每个商品类型都有单独的“表”。normalizrredux-orm 等库可以提供管理规范化数据的帮助和抽象。

¥Data with IDs, nesting, or relationships should generally be stored in a “normalized” fashion: each object should be stored once, keyed by ID, and other objects that reference it should only store the ID rather than a copy of the entire object. It may help to think of parts of your store as a database, with individual “tables” per item type. Libraries such as normalizr and redux-orm can provide help and abstractions in managing normalized data.

更多信息

¥Further information

文档

¥Documentation

文章

¥Articles

讨论

¥Discussions

我应该将表单状态或其他 UI 状态放入我的存储中吗?

¥Should I put form state or other UI state in my store?

决定 Redux 存储中应该包含什么内容的经验法则相同 也适用于这个问题。

¥The same rules of thumb for deciding what should go in the Redux store apply for this question as well.

根据这些经验规则,大多数表单状态不需要进入 Redux,因为它可能不会在组件之间共享。但是,该决定始终取决于你和你的应用。你可能会选择在 Redux 中保留某些表单状态,因为你正在编辑最初来自存储的数据,或者因为你确实需要查看应用中其他组件中反映的正在进行的值。另一方面,将表单状态保留在组件本地,并且仅在用户完成表单操作后调度一个操作以将数据放入存储中可能要简单得多。

¥Based on those rules of thumb, most form state doesn't need to go into Redux, as it's probably not being shared between components. However, that decision is always going to be specific to you and your application. You might choose to keep some form state in Redux because you are editing data that came from the store originally, or because you do need to see the work-in-progress values reflected in other components elsewhere in the application. On the other hand, it may be a lot simpler to keep the form state local to the component, and only dispatch an action to put the data in the store once the user is done with the form.

基于此,在大多数情况下,你可能也不需要基于 Redux 的表单管理库。我们建议按以下顺序尝试这些方法:

¥Based on this, in most cases you probably don't need a Redux-based form management library either. We suggest trying these approaches, in this order:

  • 即使数据来自 Redux 存储,也要从手动编写表单逻辑开始。这可能就是你所需要的。(有关这方面的一些出色指导,请参阅 Gosha Arinich 关于在 React 中使用表单的帖子。)

    ¥Even if the data is coming from the Redux store, start by writing your form logic by hand. It's likely this is all you'll need. (See Gosha Arinich's posts on working with forms in React for some excellent guidance on this.)

  • 如果你认为编写表单 "manually" 太困难,请尝试基于 React 的表单库,例如 Formik反应最终形式

    ¥If you decide that writing forms "manually" is too difficult, try a React-based form library like Formik or React-Final-Form.

  • 如果你绝对确定必须使用基于 Redux 的表单库,因为其他方法还不够,那么你最终可能想看看 Redux 形式React-Redux-Form

    ¥If you are absolutely sure you must use a Redux-based form library because the other approaches aren't sufficient, then you may finally want to look at Redux-Form and React-Redux-Form.

如果你在 Redux 中保留表单状态,则应该花一些时间考虑性能特性。在文本输入的每次击键上调度一个操作可能不值得,你可能需要研究 缓冲击键以在分派之前将更改保留在本地的方法。与往常一样,花一些时间来分析你自己的应用的整体性能需求。

¥If you are keeping form state in Redux, you should take some time to consider performance characteristics. Dispatching an action on every keystroke of a text input probably isn't worthwhile, and you may want to look into ways to buffer keystrokes to keep changes local before dispatching. As always, take some time to analyze the overall performance needs of your own application.

其他类型的 UI 状态也遵循这些经验法则。典型的例子是跟踪 isDropdownOpen 标志。在大多数情况下,应用的其余部分并不关心这一点,因此在大多数情况下它应该保持组件状态。但是,根据你的应用,使用 Redux 到 管理对话框和其他弹出窗口、选项卡、扩展面板等可能是有意义的。

¥Other kinds of UI state follow these rules of thumb as well. The classic example is tracking an isDropdownOpen flag. In most situations, the rest of the app doesn't care about this, so in most cases it should stay in component state. However, depending on your application, it may make sense to use Redux to manage dialogs and other popups, tabs, expanding panels, and so on.

更多信息

¥Further Information

文章

¥Articles