2024 年 React 状态管理的最佳选择 作者的选择

2025-05-27

2024 年的 React 状态管理

最佳选择

作者的选择

在我看来,React 状态管理库可以分为三类:

  • 基于 Reducer 的:需要调度操作来更新大型集中式状态,通常称为“单一事实来源”。这类方案包括ReduxZustand
  • 基于原子:将状态拆分成称为原子的微小数据块,可以使用 React Hooks 进行写入和读取。这类方案包括RecoilJotai
  • 基于可变的:利用代理创建可变数据源,可以直接写入或被动读取。这类方案的候选者包括MobXValtio

现在我们已经介绍了 React 状态管理库的三大类。让我们深入研究每一种,并探讨每种方法的优缺点。这将帮助你了解哪个库最适合你的项目需求:

1.基于Reducer的库:

尽管人们普遍批评 Redux 过于复杂,但它自创建以来一直是最受欢迎的状态管理库。



+---------------------+
|        Actions      |
+----------|----------+
           |
           v
+---------------------+        +---------------------+
|        Reducers     |        |       Store         |
+----------|----------+        +----------|----------+
           |                              |
           v                              v
+---------------------+        +---------------------+
|        State        |        |     Subscriptions   |
+---------------------+        +---------------------+


Enter fullscreen mode Exit fullscreen mode

优势:

  • 强大的状态机和时间机器。假设您的所有应用程序状态都位于集中式状态中(这种情况很少发生,因为您的组件中可能存在本地状态),则将存在以下公式:UI = React(state)。这意味着单个状态值只会导致一个UI,因此您的应用程序在特定状态下的外观将始终相同。如果您在某个地方备份整个状态,然后调度类似 的更改REVERT(pastState) { state = pastState },您的UI将恢复,就像它是截取的屏幕截图一样。

  • 最佳 DevTools 支持:通过使用显式操作更新状态,DevTools 可以帮助您指出状态变化的内容、时间和方式。您可以想象这就像在应用程序状态中拥有 Git 提交历史记录一样,是不是很酷?
    提交消息 meme。来源:https://medium.com/@hritik.jaiswal/how-to-write-a-good-commit-message-9d2d533b9052

弱点:

  • 样板代码:即使对状态进行简单的更改也需要对代码进行大量更改。
  • 学习曲线陡峭:虽然核心简单,但仅凭其本身远远不够。要真正掌握 Redux,你应该知道如何将它与其他库(例如 Saga、Thunk、Reselect、Immer 或 Redux Toolkit)结合使用。大多数情况下,我们只是在 Saga 中使用生成器来通过网络获取一些数据,这感觉有些过度。现代 JS 开发人员倾向于每天使用 async/await。
  • TypeScript:虽然完全支持 TypeScript,但大多数情况下需要显式输入才能完成操作、reducer、选择器和状态的类型识别。其他方法则直接支持自动类型推断。

2.基于Atom的库:

这种方法不是将整个应用程序的状态放在一个大型的集中式状态中,而是将其拆分成多个原子,每个原子最好尽可能小,例如原始类型或数组和扁平对象等基本数据结构。然后,如果需要,您可以使用选择器将相关状态分组。



+---------------------+
|     Atoms (State)   |
+----------|----------+
           |
           v
+---------------------+        +---------------------+
|  Selectors (Derived |        |   RecoilRoot        |
|     State)          |        +----------|----------+
+----------|----------+                   |
           v                              v
+---------------------+        +---------------------+
|    State Snapshot   |        |   React Components  |
+---------------------+        +---------------------+


Enter fullscreen mode Exit fullscreen mode

优势:

  • 利用 React 功能:由于 Recoil 和 React 均由 Facebook 开发,因此这一点在意料之中。Recoil 与 React 的前沿功能(例如 Suspense、Transition API 和 Hooks)完美兼容。

  • 简单易用且可扩展:仅使用原子和选择器,您仍然可以高效地构建大型响应式应用状态,同时对单个状态变更进行细粒度的控制。现在,状态提升非常简单,只需声明一个原子并将useState钩子更改为 即可useRecoilState

  • TypeScript:作为一名开发者,我关注 DX 就像用户关注 UI 和 UX 一样重要,我发现 React、Recoil 和 TypeScript 是一个绝佳的组合。在我的项目中,大多数情况下类型都是自动推断的。

弱点:

  • DevTools:如果您正在寻找与 Redux DevTools 相当的工具,很遗憾,没有。

  • 无法在组件外部使用状态:尽管 Recoil Nexus 是一种解决方法,但这种状态管理库的设计是基于一个(可能是真的)假设,即所有状态的使用都发生在 React 组件内部。

  • 尚不稳定:四年过去了,Recoil 的最新版本(v0.7.7)仍然以 0 开头。我希望,当你读到这篇文章的时候,这些信息已经不再重要了。

3.基于可变的库:

提示:“可变”和“不可变”是指数据在创建后如何被更改:

  • person.age += 1 // mutable
  • person = { …person, age: person.age + 1 } // immutable


+---------------------+
|     Observables     |
+----------|----------+
           |
           v
+---------------------+        +---------------------+
|   Computed Values   |        |     Actions         |
+----------|----------+        +----------|----------+
           |                              |
           v                              v
+---------------------+        +---------------------+
|   Reaction (Derived |        |    MobX Store       |
|       Value)        |        +----------|----------+
+---------------------+                   |
                                          v
                               +---------------------+
                               |   React Components  |
                               +---------------------+


Enter fullscreen mode Exit fullscreen mode

优势:

  • 最简单的 API:通过允许状态直接改变,除非您愿意,否则不需要在组件和状态之间放置样板代码。
  • 响应性和灵活性:依赖项会在状态发生变化时自动更新。这简化了应用程序逻辑,使其更易于理解。此外,基于代理的方法有助于最大限度地减少不必要的重新渲染。这也意味着流畅的性能和更灵敏的用户体验。

弱点:

  • 魔法太多:自动响应式是一把双刃剑。异步更新中的竞争条件可能会导致应用程序状态混乱,并且在复杂的应用程序中调试变更流程可能非常困难。
  • DevTools:再次强调,在我看来,没有任何替代方案能像基于 Reducer 的方法那样提供最好的工具支持。
  • 离散 DX:虽然 React 详细阐述了“不可变”方法,但在我的项目中混合使用“可变”数据有时会让我对如何更改数据感到不安全。

最佳选择

再次强调,最适合你项目的 React 状态管理库取决于你和你团队的具体需求和专业知识。请不要

  • 仅根据项目规模和复杂程度来选择库。你可能听说过,X 更适合大型项目,而 Y 更适合小型项目。库的作者在设计库时就考虑到了可扩展性,而项目的可扩展性取决于你如何编写代码和使用库,而不是你选择使用哪个库。

  • 将你从一个库学到的最佳实践应用到另一个库。将整个应用程序状态放在一个 Recoil 原子中以实现“单一事实来源”只会导致状态更新困难和性能问题。此外,在 Redux 中将操作定义为 setter 并分派多个操作,而不是在一次提交中批量更改。

作者的选择

TL;DR:Jotai。

我个人更喜欢原子库,因为它有上面列出的优势,而且我之前用 处理异步数据获取和批量加载 UI 时,DX 体验非常流畅<Suspense>。Jotai 比 Recoil 强的地方在于:

  • 无需密钥。命名很麻烦,而且大多数情况下,您不会使用 Recoil 的密钥。既然库可以自动为您获取密钥,为什么还要花时间声明它们呢?这是Recoil 的答案;然而,正如您所见,人们对此并不十分信服。
  • 性能。一张图片胜过千言万语,我有 4 张图片:

图书馆 进口成本 液晶聚合物
畏缩 反冲进口成本 后坐力用途的LCP
乔泰 Jotai进口成本 Jotai 使用的 LCP

你可能会认为约 20KB 的大小差异无关紧要,但让我们来看看在一台非常老旧的 Android 设备上进行的基准测试,其中的缓慢表现得非常明显,就像用红色斜条纹填充的条形图一样。正如你所见,Jotai 的内部逻辑需要更少的整体计算,这使得我的应用程序的 LCP(一个重要的 Core Web Vitals 指标)从约 2.6 秒提升到了约 1.2 秒。尽管如此,这种比较可能没有考虑到 Recoil 在其他方面比 Jotai 做得更好的因素(事实上,这是我在这方面的知识范围)。我只想说,Jotai 团队在这方面做得非常出色。

我希望这有帮助!

文章来源:https://dev.to/nguyenhongphat0/react-state-management-in-2024-5e7l
PREV
💜 React Hooks 学习合集!🎣
NEXT
使用您的 CSV 聊天:使用 Langchain 和 Streamlit 可视化您的数据