2021 年 React 状态管理之战:Hooks、Redux 和 Recoil
介绍:
多年来,React.JS 的迅猛发展催生了各种状态管理库。
截至撰写本文时,我们掌握的 React 状态管理库数量庞大。因此,了解为特定项目选择哪种状态管理库,避免被 React 社区的喧嚣和新闻所迷惑,是促进应用程序开发的重要因素。
一些开发人员使用 React Hooks 来应对挑战;另一些开发人员则将其与 Redux 或新发布的 Recoil 等应用程序状态管理库结合使用。
在本文中,我们将讨论在典型的 React 应用程序中使用 Redux、Hooks 和 Recoil 进行状态管理及其最佳用例。
我们还将尝试回答以下问题:
- 在选择状态管理库之前要考虑哪些指标?
注意:本教程将对有兴趣开发需要状态管理库的 React 应用程序的读者有所帮助。
本文并非 React 状态管理的入门介绍。它需要对 React、Hooks 和一些 Redux 有基本的了解;因此,如果您是 React 新手,并且想学习 React 中的状态管理,请在开始本教程之前先了解这些基础知识 😎。
简而言之,状态是什么?
状态管理只是一种在组件之间进行通信和数据共享的方式。它创建了一个具体的数据结构来表示应用程序的状态,您可以读写该状态。
从 React 16.8 开始,每个 React 组件(无论是函数式组件还是类组件)都可以拥有状态。
最简单的定义是,State 是一个 JavaScript 对象,它表示组件中可以根据用户的操作而变化的部分。您也可以说状态只是组件的内存。
当用户在典型的 React 应用中执行操作时,组件的状态会发生变化。虽然这本身并不坏,但如果应用开始扩展,很快就会成为一个问题;因此,这种应用的复杂性使得跟踪所有依赖关系变得极其困难。
为了回答引言的问题,假设我们正在构建一个电子商务应用程序;在这样的应用程序中,几乎每个元素都可以成为一个组件——购物车、按钮、查看购物车会话、结帐、登录栏等。在这个应用程序中,只需一个添加到购物车的用户操作就可以通过以下方式影响许多其他组件:
- 改变购物车组件本身的状态,
- 将购物车添加到用户的购物车历史记录中,
- 结帐产品项目。
以上只是我们能添加到电商应用中的众多功能中的一小部分。如果负责开发的工程师在开发应用时不考虑可扩展性,那么从长远来看,他们可能很快就会遇到许多 bug 和问题。
像这样不断地调试和修改应用最终可能会非常痛苦。
上述场景向我们展示了状态在典型的 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 进行状态管理的一些权衡。
社区支持
作为 React 和 Redux 的官方绑定库,React-Redux 拥有庞大的用户社区,让您可以更轻松地寻求帮助、学习最佳实践、使用基于 React-Redux 构建的库,并在不同应用程序中复用您的知识。
它是 Github 上关注度最高的 React 状态管理库。
增强性能
React Redux 确保性能优化,以便只有连接的组件才在需要时重新渲染;因此保持应用程序的状态全局不会导致任何问题。
Redux 使状态可预测。
在 Redux 中,状态始终是可预测的。如果将相同的状态和操作移动到 Reducer,由于 Reducer 是纯函数,因此将获得相同的结果。状态也是不可变的,永远不会改变。这使得执行诸如无限次撤消和重做等艰巨任务成为可能。它还可以实现时间旅行——即在先前状态之间来回移动并实时查看结果的能力。
本地存储状态持久化
可以将应用的部分状态持久化到本地存储,并在刷新后恢复。这使得在本地存储中存储购物车数据等数据变得非常棒。
服务端渲染
我们也可以使用 redux 进行服务端渲染。通过它,你可以将应用的状态及其对服务器请求的响应发送到服务器,从而处理应用的初始渲染。
Redux 易于维护。Redux
对代码设计非常严格,即使熟悉 Redux 的用户也能轻松理解任何 Redux 应用程序的结构。这通常使其更易于维护。它还能帮助您将业务逻辑与组件树分离。对于大型应用而言,保持应用更可预测且更易于维护至关重要。
调试变得简单
Redux 让应用程序调试变得简单。通过记录操作和状态,可以轻松了解生产过程中可能出现的编码错误、网络错误和其他形式的错误。
除了日志记录之外,它还拥有出色的 DevTools,允许您进行时间旅行操作、在页面刷新时保留操作等。对于中大型应用程序来说,调试比实际开发功能花费的时间更多。
虽然 Redux 有其优点,但这并不意味着你必须在所有应用中都添加 Redux。
你的应用即使没有 Redux 也能运行良好。
畏缩
Recoil 似乎是状态管理社区中最新的工具——该社区拥有大量优秀的库,如 Context、Mobx 和 Redux 等。
在详细介绍 Recoil 之前,我想指出的是,这个新的状态管理库并非 React 的“官方”状态管理库。
然而,记录显示它是由 Facebook 团队(React 的缔造者)的工程师构建和发布的。
不过,正如 Redux 并非 React 的官方状态管理库一样,Recoil 也不是,但如果它被证明对整个 React 生态系统有价值,它可能会得到 React 爱好者的大规模采用。
Recoil 解决的主要问题
虽然它有其学习难度,但它仍然解决了与大多数其他状态管理库相同的问题:全局状态管理。
在使用了一段时间后,我认为 Recoil 的一些优点非常有用。
类似 React 的方法和简洁性
Recoil 的简洁性首屈一指,这也是它入选此榜单的原因。
你可以像使用 Redux 或 MobX 一样,用 Recoil 构建任何应用。
然而,Recoil 的使用体验就像是 React useState 的全局版本。它还支持并发模式,这是一个巨大的优势(撰写本文时,此功能仍在开发中)。
轻松的学习曲线
Recoil 不像 Redux 和 Mobx 那样要求严格的学习曲线。
除了 Atom 和 Selectors 之外,其他方面都比较容易理解。
应用范围的观察
与其他状态管理库类似,Recoil 能够很好地处理应用范围的状态观察。使用 Recoil 的其他好处包括:
- 无样板 API
- 分布式增量状态定义
Recoil 的核心概念是原子 (Atom) 和选择器 (Selector);本文不打算介绍这部分内容。不过,您可以查看他们的文档以获得更深入的概述。
何时使用后坐力
在发布不到两年的时间里,Recoil 的发展势头迅猛,截至本文撰写时,它在 Github 上已获得超过 1.2 万颗星。除此之外,它在 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 需要一些样板代码才能在我们的应用中运行;因此,这带来了不必要的复杂性。
另一方面,有了useContext
API 和 React Hooks,我们无需安装外部库即可运行应用。这使得在 React 应用中处理全局状态管理变得更加简单、直接。
注意:假设您已经熟悉useState
,我们将研究两个有助于 React 中状态管理过程的钩子。
钩子useReducer
HookuseReducer
是 React 16.8 中引入的。与 JavaScript 中的方法类似reduce()
,useReducer
Hook 接收两个值作为参数——一个 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>
)
useContext
此钩子用于获取提供程序的当前上下文。为了创建并提供上下文,我们使用React.createContext
API。
const myContext = React.createContext()
我们将根组件放在myContext
Provider 之间:
function App() {
return (
<myContext.Provider value={900}>
<Root />
</myContext.Provider>
)
}
为了使用我们提供的值,<myContext.Provider></myContext.Provider>
我们使用useContext
钩子。
function Root() {
const value = useContext(myContext)
return (
<>
<h3>My Context value: {value} </h3>
</>
)
}
使用 useReducer 和 useContext
useContext 与 useReducer 结合使用,将组件共置状态管理提升到了一个新的高度。这样一来,我们就可以将 useReducer 创建的状态容器及其 dispatch 函数从任何顶层组件传递给任何组件。它也可以作为最顶层的组件,使状态“全局化”。虽然仅使用 React props 向下传递数据也是可行的,但 React 的 Context API 使你的状态和 dispatch 函数可以在任何地方使用,而无需显式地将所有内容传递到组件树的下游。
结论
在本文中,我们尝试介绍 2021 年最流行的 React 状态管理工具,它们在 React 状态管理中如何发挥重要作用,以及在项目中何时使用它们。
我很想了解您在典型的 React 应用程序中管理状态的经验。
资源
- 何时(以及何时不)使用 Redux - Christian Nwamba
- React State Hooks:useReducer、useState、useContext - Robin Weiruch
- Recoil 的实际应用:构建可重用的代码块组件- Tomi Odunsanya
- 重构 Redux 应用程序以使用 Recoil - Ohans Emmanuel
- 为什么 React 项目仍然使用 Redux - Alexandru-Dan Pop
本文作者是 Blessing Krofegha,最初发表于JavaScript Works。
文章来源:https://dev.to/workshub/state-management-battle-in-react-2021-hooks-redux-and-recoil-2am0