编者注 :本文于 2022 年 9 月 23 日更新,添加了关于为什么我们需要在 React 中进行状态管理的信息,添加了之前未包含在文章中的其他状态管理工具,例如 Jotai、MobX 和 Zusand,并添加了有关哪些状态管理的信息工具是 React 的最佳选择。
状态管理是每个开发人员在构建 React 应用程序时面临的基本挑战——而且它不是一个小问题。 在 React 中有很多有效的管理状态的方法,每一种都解决了一组突出的问题。
作为开发人员,重要的是不仅要了解不同的方法、工具和模式,还要了解它们的用例和权衡。
考虑状态管理的一个有用方法是根据我们在项目中解决的问题。 在本文中,我们将介绍在 React 中管理状态的常见用例,并了解何时应该考虑使用每种解决方案。 我们将通过构建一个简单的计数器应用程序来实现这一点。
-
为什么我需要在 React 中进行状态管理?
-
React 中的本地组件状态
-
React 中的组件道具
-
React 中的路由
-
使用 React 的 Context API useReducer
-
使用 Redux 进行状态管理
-
带有 Recoil 的原子状态
-
带有 XState 的状态机
-
使用 Jotai 进行原始和灵活的状态管理
-
使用 MobX 进行简单、可扩展的状态管理
-
使用 Zustand 进行状态管理
-
使用 React Query 获取数据
-
哪种状态管理工具最适合 React?
为什么我需要在 React 中进行状态管理?
首先,让我们讨论一下状态管理的重要性。 React 中的状态是一个 JavaScript 对象,它可以根据用户的操作来改变组件的行为。 状态也可以被认为是组件的内存。
React 应用程序是使用管理自己状态的组件构建的。 这适用于小型应用程序,但随着应用程序复杂性的增加,处理组件之间的共享状态变得越来越复杂和成问题。
这是一个简单的示例,说明金融科技应用程序中的成功交易如何影响其他几个组件:
-
新交易将更改首页显示的可用余额
-
新交易现在将显示为用户总交易历史中的最新交易
这就是为什么在开发可扩展的 React 应用程序时状态管理必不可少的原因。 从长远来看,如果状态管理不正确,应用程序无疑会遇到问题。 像这样不断地对应用程序进行故障排除和重建可能会变得乏味。
React 中的本地组件状态
实现计数器的最简单方法是使用本地组件状态和 useState钩。
import { useState } from 'react' const Counter = () => { const [count, setCount] = useState(0) const increaseCount = () => { setCount(count + 1) } const decreaseCount = () => { if (count > 0) { setCount(count - 1) } } return ( <div> <h1>{count}</h1> <button onClick={decreaseCount}>-</button> <button onClick={increaseCount}>+</button> </div> ) } export default Counter
所以我们完成了,对吧? 文章结束? 不完全的。
超过 20 万开发人员使用 LogRocket 来创造更好的数字体验 了解更多 →
如果这是一个真正的项目,那么将来我们可能会在应用程序的其他地方需要更多按钮和标题。 确保它们的外观和行为一致是一个好主意,这就是为什么我们应该将它们变成可重用的 React 组件的原因。
React 中的组件道具
转动我们的 Button和 Header分成不同的组件揭示了一个新的挑战。 我们需要某种方式在它们和主节点之间进行通信 Counter零件。
这就是组件道具发挥作用的地方。 对于我们的 Header组件,我们添加一个 text支柱。 对于我们的 Button,我们都需要一个 label道具和一个 onClick打回来。 我们的代码现在看起来像这样:
import { useState } from 'react' const Header = ({ text }) => <h1>{text}</h1> const Button = ({ label, onClick }) => ( <button onClick={onClick}>{label}</button> ) const Counter = () => { const [count, setCount] = useState(0) const increaseCount = () => { setCount(count + 1) } const decreaseCount = () => { if (count > 0) { setCount(count - 1) } } return ( <div> <Header text={count} /> <Button onClick={decreaseCount} label="-" /> <Button onClick={increaseCount} label="+" /> </div> ) } export default Counter
这看起来很棒! 但是想象一下下面的场景:如果我们只需要在我们的家乡路线上显示计数并且有一个单独的路线怎么办? /controls我们在哪里显示计数和控制按钮? 我们应该怎么做呢?
React 中的路由
鉴于我们正在构建一个单页应用程序,现在我们需要处理第二个状态——我们所在的路线。 例如,让我们看看如何使用 React Router 来完成。
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom' import { useState } from 'react' const Header = ({ text }) => <h1>{text}</h1> const Button = ({ label, onClick }) => ( <button onClick={onClick}>{label}</button> ) const Home = ({ count }) => { return <Header text={count} /> } const Controls = ({ count, decreaseCount, increaseCount }) => { return ( <> <Header text={count} /> <Button onClick={decreaseCount} label="-" /> <Button onClick={increaseCount} label="+" /> </> ) } const App = () => { const [count, setCount] = useState(0) const increaseCount = () => { setCount(count + 1) } const decreaseCount = () => { if (count > 0) { setCount(count - 1) } } return ( <Router> <nav> <Link to="/">Home</Link> <Link to="/controls">Controls</Link> </nav> <Switch> <Route path="/controls"> <Controls increaseCount={increaseCount} decreaseCount={decreaseCount} count={count} /> </Route> <Route path="/"> <Home count={