多年来,React.JS 的大规模增长催生了不同的状态管理库等。
在撰写本文时,我们可以使用 React 中可用的状态管理库是巨大的。因此,知道为特定项目选择哪个状态管理库以免被来自 React 社区的噪音和新闻所迷惑是促进应用程序开发的重要因素。
一些开发人员通过使用 React Hooks 来应对挑战;其他人将它们与 Redux 或新发布的 Recoil 等应用程序状态管理库相结合。
在本文中,我们将讨论在典型的 React 应用程序中使用 Redux、Hooks 和 Recoil 进行状态管理及其最佳用例。
我们还将尝试回答以下问题:
在选择状态管理库之前要考虑什么指标?
注意:本教程将对有兴趣开发需要状态管理库的 React 应用程序的读者有所帮助。
本文不是 React 状态管理的介绍。它需要对 React、hook 和一些 Redux 有基本的了解;因此,如果您开始使用 React 和 React 中的状态管理,请在开始本教程之前先了解这些基础知识。
简而言之,什么是状态?
状态管理只是一种实现跨组件通信和数据共享的方式。它创建了一个具体的数据结构来表示您可以读写的应用程序状态。
从 React 16.8 开始,每个 React 组件,无论是函数式还是类,都可以有一个状态。
在最简单的定义中,State 是一个 JavaScript 对象,它表示可以根据用户的结果操作更改的组件部分。您也可以说状态只是组件的内存。
当用户在典型的 React 应用程序中执行操作时,组件的状态会发生变化。虽然这还不错,但如果应用程序开始扩展,它很快就会成为一个问题;因此,这样一个应用程序的复杂性使得跟踪所有依赖项变得非常困难。
为了回答介绍问题,假设我们正在构建一个电子商务应用程序;在这样的应用程序中,几乎每个元素都可以是一个组件——购物车、按钮、查看购物车会话、结帐、登录栏等。在这个应用程序中,添加到购物车的单个用户操作可以影响许多其他组件通过:
- 改变购物车组件本身的状态
- 将购物车添加到用户的购物车历史记录中
- 结帐产品项目
这只是提到我们可以添加到电子商务应用程序的其他大量内容中的一些内容。如果负责工程师在开发应用程序时不考虑可扩展性,从长远来看,他们很快就会遇到许多错误和问题。
像这样不断调试和改进应用程序最终可能会很痛苦。
上述场景向我们展示了状态在典型 React 应用程序中的重要性。
在管理此应用程序中的状态时,我们可以使用我们选择的任何库;无论如何,他们仍然会完成工作。
通常,状态必须被提升到最近的父组件和下一个,直到它到达需要状态的两个组件的共同祖先,然后它被传递下来。这个过程可能是压倒性的,并使状态难以维持。通常,您可能需要将数据传递给甚至不需要它的组件。
随着应用程序变大,状态管理变得混乱。这就是为什么您需要像 Redux、Recoil 这样的状态管理工具,以便更轻松地维护这些状态。
在接下来的部分中,我们将实际了解所有状态管理库(Redux、Hooks、Recoil)、它们的独特性以及在使用它们之前需要考虑的事项。
Redux
我们列表中的第一个是 Redux;它已经存在了一段时间,几乎是第一个基于 React 的状态管理库。
创建状态管理库 Redux 是为了解决我们电子商务应用程序中的问题。它提供了一个名为 store 的 JavaScript 对象,一旦设置,它就会包含应用程序中的所有状态,并在必要时更新它们。这是 Redux 工作原理的简化可视化。
也许你会问,为什么 Redux 经常与 React 一起使用?我的经验是因为 Redux 会根据用户的操作来处理状态更新,尤其是在 UI 中;除此之外,Redux 可以用作任何框架的独立状态管理。
什么时候使用 Redux?
截至本文撰写之时,Redux 是最流行的 React 状态管理库之一。
在本节中,我们将仔细研究何时在应用程序中使用 Redux。
首先,Redux 允许您在一个地方管理应用程序的状态,并使应用程序中的更改更具可预测性和可追溯性。它使您的应用程序中发生的更改更容易弄清楚。不幸的是,所有这些好处都伴随着特定的限制和权衡。
通常,开发人员觉得使用 Redux 会增加一些样板代码,使小事情看起来势不可挡;然而,这完全取决于应用程序的架构决策。
了解何时真正需要使用 Redux 的最简单方法之一是在本地管理状态开始变得混乱时。
随着应用程序的增长,跨组件的状态共享也会变得乏味。
那时,您现在就开始寻找使流程轻松的方法。
在下一节中,我们将看看为什么我们应该使用 React 进行 Redux。
为什么要使用 Redux?
使用 Redux 和 React 消除了管理状态的麻烦,让你更容易追踪哪个动作导致了任何变化,从而简化了应用程序并使其更容易维护。
让我们来看看使用 Redux 进行状态管理带来的一些权衡。
(1) 社区支持
作为 React 和 Redux 的官方绑定库,React-Redux 包含了庞大的用户社区。这使得寻求帮助、了解最佳实践、使用基于 React-Redux 构建的库以及在不同应用程序中重用您的知识变得更加容易。
它是 Github 上最受关注的 React 状态管理库。
(2) 增强性能
React Redux 确保性能优化,以便只有连接的组件仅在需要时重新渲染;因此保持应用程序的状态全局不会导致任何问题。
(3) Redux 使状态可预测
在 Redux 中,状态始终是可预测的。如果相同的 state 和 action 移动到 reducer,它会得到相同的结果,因为 reducer 是纯函数。状态也是不可变的,永远不会改变。它使执行诸如无限撤消和重做之类的艰巨任务成为可能。还可以实现时间旅行——即在之前的状态之间来回移动并实时查看结果的能力。
(4) 本地存储上的状态持久性
将应用程序的某些状态保留在本地存储上并在刷新后恢复它是可能的。它使得在本地存储上存储诸如购物车数据之类的东西真的很棒。
(5) 服务端渲染
我们也可以使用redux进行服务端渲染。有了它,您可以通过将应用程序的状态连同它对服务器请求的响应发送到服务器来处理应用程序的初始呈现。
(6) Redux 是可维护的
Redux 对代码应该如何设计很严格,这使得熟悉 Redux 的人更容易理解任何 Redux 应用程序结构。它通常更易于维护。它还可以帮助您将业务逻辑与组件树分离。对于大型应用程序,让您的应用程序更具可预测性和可维护性至关重要。
(7) 调试变得容易
Redux 使调试应用程序变得容易。通过记录操作和状态,很容易理解编码错误、网络错误和生产过程中可能出现的其他形式的错误。
除了日志之外,它还有优秀的 DevTools,可以让你对动作进行时间旅行,在页面刷新时保持动作等。对于中大型应用程序,调试比实际开发功能需要更多的时间。
尽管 Redux 有其优点,但并不保证您在所有应用程序中都添加了 Redux。
您的应用程序可以在没有 Redux 的情况下运行良好。
Recoil
Recoil 似乎是状态管理社区的最新工具——一个拥有大量优秀库的社区,如 Context、Mobx 和 Redux 等。
在详细介绍 Recoil 之前,我想指出这个新的状态管理库并不是 React 的“官方”状态管理库。
然而,记录显示它是由 Facebook 团队的工程师,即 React 创建者构建和发布的。
但是,正如 Redux 不是 React 的官方状态管理库一样,Recoil 也不是,但如果它被证明对整个 React 生态系统有价值,那么它可能会被 React 爱好者广泛采用。
Recoil 解决的主要问题
虽然它有它的学习曲线,但它仍然解决与大多数其他状态管理库相同的问题:全局状态管理。
在使用 Recoil 一段时间后,以下是我认为 Recoils 非常方便的区别。
(1) 类似 React 的方法和简单
Recoil 的简单性是首屈一指的,因此它在此列表中的原因。
您可以像使用 Redux 或 MobX 一样构建使用 Recoil 构建的任何应用程序。
然而,Recoil 感觉就像在使用 React 的 useState 的全球版本。它还支持并发模式,这是一个巨大的优势(在撰写本文时仍在进行中)。
(2) 简单的学习曲线
Recoil 不像 Redux 和 Mobx 那样强加严格的学习曲线。
除了易于理解的 Atom 和 Selectors 之外,它们不需要学习太多。
(3) 应用程序范围的观察
与其他状态管理库类似,Recoil 可以很好地处理应用程序范围的状态观察。使用 Recoil 的其他好处包括:
- 无样板 API
- 分布式和增量状态定义
Recoil 的核心核心概念是原子和选择器;涵盖这一部分超出了本文的范围。但是,您可以查看他们的文档以获得深入的概述。
何时使用Recoil
在发布不到两年的时间里,Recoil 已经发展得如此之快,以至于在撰写本文时,它在 Github 上拥有大约 12,000 颗星。除此之外,它在 React 爱好者和整个 React 社区中逐渐获得动力和大规模采用。
就个人而言,我在我的任何项目中使用 Recoil 的唯一原因是我不打算在我的代码库中有这么多 Redux 样板。我曾经在生产中使用过 Recoil,没有发生任何可怕的事情;到目前为止,一切仍然运行良好。
所以什么时候使用 Recoil 可能完全取决于你的应用程序的架构决定,如果你和我一样喜欢简单,你可能会开始使用 Recoil 。
使用 React Hooks
Hooks 是 React 库自创建以来添加的最杰出的特性之一。Hooks 为功能组件带来了“状态”。现在,功能组件可以自己创建和管理本地状态,就像类组件一样。
任何已经接触过 React 的人都应该熟悉 React Hooks,包括useState、useEffect、 和useReducer等。
本节将讨论如何方便的 React Hooks 可以独立使用,而无需与任何外部状态管理库相互干扰。
你可以在没有任何库的情况下使用 React Hooks 作为你的主要状态管理工具,但这取决于你对 React Hooks 的经验和理解。
它们本身就很强大,几乎可以完成外部库可以做的任何事情。
在某种程度上,其他状态管理工具具有一些优势。尽管如此,他们的程序使入门具有挑战性。就像 Redux 一样,需要一些样板代码才能让它在我们的应用程序中工作;因此,它引入了不必要的复杂性。
另一方面,使用useContextAPI 和 React Hooks,无需安装外部库即可让我们的应用程序正常运行。它使它成为一种更简单、更直接的方式来处理 React 应用程序中的全局状态管理。
注意:假设您已经熟悉useState,我们将研究两个有助于 React 状态管理过程的Hooks。
useReducer
该useReducer来自React 16.8。就像reduce() JavaScript 中的方法一样,useReducerHook 接收两个值作为它的参数——一个 reducer 函数和一个初始状态——然后返回一个新状态:
- const [state, dispatch] = useReducer((state, action) => {
- const { type } = action;
- switch(action) {
- case 'action description':
- const newState = // do something with the action
- return newState;
- default:
- throw new Error()
- }
- }, []);
在上面的代码片段中,我们定义了我们的状态和相应的方法dispatch,来处理它。当我们调用该dispatch方法时,useReducer() Hook 将根据type我们的方法在其 action 参数中接收到的来执行操作:
- ...
- return (
- <button onClick={() =>
- dispatch({ type: 'action type'})}>
- </button>
- )
使用上下文
此钩子用于获取 Provider 的当前上下文。为了创建和提供上下文,我们使用React.createContextAPI。
- const myContext = React.createContext()
我们将根组件放在myContextProvider之间:
- function App() {
- return (
- <myContext.Provider value={900}>
- <Root />
- </myContext.Provider>
- )
- }
为了消耗由
- function Root() {
- const value = useContext(myContext)
- return (
- <div>
- <h3>My Context value: {value} </h3>
- </>
- )
- }
使用 useReducer 和 useContext
将 useContext 与 useReducer 一起使用可以在另一个级别上将组件并置状态管理。突然间,我们可以将 useReducer 创建的状态容器及其调度函数从任何顶级组件传递给任何组件。它也可以是使状态“全局化”的最顶层组件。也可以仅使用 React props 向下传递内容,但是 React 的 Context API 使您的状态和调度函数可以在任何地方使用,而无需显式地将所有内容向下传递到组件树。
结论
在本文中,我们试图介绍 2021 年最流行的 React 状态管理工具,它们如何在 React 状态管理中发挥重要作用,以及何时在项目中使用它们。
我想知道您在典型 React 应用程序中管理状态的经验。