[双语对照]react 状态管理的前世,今生和未来

译者注:

其实这篇文章并没有太多的干货,但是它提供了时间维度的视角让我们去观察状态管理是怎么发展;这段简短的历史可以作为我们选择状态管理的参考资料,也可以作为一个技术雷达帮我们发现一些技术广度上的盲点。

而我自知翻译仓促和语言能力匮乏,所以留下原文供大家参考;如果有更好的翻译建议和批评可以偷偷告诉我。

全文最有价值的部分可能就是未来部分“关于状态管理如何选择”的部分,不想看水文的可以直接划到最下面。

原文地址 https://leerob.io/blog/react-state-management

React was introduced in May 2013. Its paradigm shift was that your UI was a function of your state. Given some component state, React can determine what your component will look like. React is built upon the idea of state. However, state has long been one of the most difficult parts of building a React application.

自2013年5月面世以来,React 给前端带来了新的编程范式:UI 是状态的函数。给定组件一个状态,React 就能决定这个组件的样子。React 就是基于状态的概念来开发的。但是长久以来状态管理是使用 React 开发应用时最头痛的问题。

Let's imagine state management in React as a rugged tool belt. You've used this tool belt for years, slowly adding new tools as needed. Each tool serves a very specific purpose. You don't use your hammer to screw in bolts. As a craftsman, you've learned the right time and place to use each tool.

如果把 React 中状态管理比喻成一个工具箱,里面有一些你已经使用多年的老工具,而且你也会根据不同需要逐渐添加新的工具。每种工具用来解决一个特定的问题。作为代码匠,你知道在不同情况下使用不同工具来解决问题,绝不会用榔头来拧螺丝。

State management with React is a rugged tool belt, but not everyone has the prior experience to know which tool to reach for. This post will explain the past, present, and future of state management to help you make the correct decision for your team, project, or organization.

React的状态管理是一个重要的工具箱,但是并不是每个人都有如何筛选工具的经验。这篇文章就是想和大家厘清状态管理的前世,今生和未来,来帮助大家在团队、项目和组织中选择合适的状态管理工具。

名词解释 Glossary

Before we begin, it's critical you understand some of the terms commonly used. These aren't the canonical names. A few different variations of each float around, but the underlying ideas are the same:

在文章正式开始前,我们先定义下常用的几个名词解释。这些定义并不是专业定义,实际使用的时候也会有些变化,但是背后的概念是一样的。

UI State State used for controlling interactive parts of our application (e.g. dark mode toggle, modals).

UI 状态 - 用来控制如何应用(如主题设置,模态窗口)如何交互的状态。

Server Cache State – State from the server, which we cache on the client side for quick access (e.g. call an API, store the result, use it in multiple places).

远程缓存状态 - 将服务端的状态缓存在客户端,以便方便使用。(比如,调用一个 API,然后将结果保存,然后在各个组件中使用)

Form State The many different states of a form (e.g. loading, submitting, disabled, validation, retrying). There's also controlled & uncontrolled form state.

表单状态 - 表单的各种状态(例如:加载中,提交中,按键不可用,字段校验失败,重试等等),这些状态也分为受控状态和非受控表单状态。

URL State - State managed by the browser (e.g. filter products, saving to query parameters, and refreshing the page to see the same products filtered)

URL 状态 - 由浏览器管理的链接状态(例如:一个过滤功能,将过滤参数存储在 URL 中,这样刷新页面还是能看到相同的列表结果)[译者:其实就是路由状态管理]

State Machine - An explicit model of your state over time (e.g. a stoplight goes from green → yellow → red, but never green → red).

状态机 - 明确定义状态随时间变化的模型,比如红绿灯的状态机:从绿灯-> 黄灯-> 红灯,但是不能直接从绿灯直接变成红灯。

前世 past

React's component model helped create reusable, composable applications. Each component had its own local state. As web apps became more complex, new solutions emerged to more easily share logic between components.

React的组件模型让我们能够构建出可复用、可组合的应用。每个组件都有自己的独立状态。当 Web 应用变得越来越复杂,一些新的管理方案应运而生,来解决组件之间如何方便共享复用逻辑的问题。

时间线

To help you understand how state management has evolved over time, here's a rough timeline of popular state management solutions in React. This list is heavily focused on UI State. This list is not comprehensive, but is enough to give context.

为了帮大家更好地理解状态管理发展的历史,我梳理了React 中状态管理库的流行趋势。这些列表主要是 UI 的状态管理的库,所以不是很全面,但是也足以说明问题。

2013 状态管理萌芽时期

2014 Flux时代

2015 Redux

2016 MobX

2018 Context

2019 Hooks引入(同时诞生了 React Query 和 SWR)

2019 Zustand

2019 基于状态机的 xState 

2020 Jotai, Recoil, Valtio

2021 useSelectedContext

Just because an item is listed on this timeline does not mean you need to learn it. More on this later. Let's dive into the history of state management in React.

只是按照时间顺序罗列了这些状态管理库,并不表示你需要掌握每一个。接下来我一起来深入了解下 React 中的状态管理。

Redux

Redux was originally created as an implementation of the "Flux Architecture", which was a pattern first suggested by Facebook in 2014. Redux came out in 2015 and quickly became the most popular of many Flux-inspired libraries. It's ecosystem of tools and libraries encapsulated both UI state and server caching state. Redux is still extremely popular and widely used.

2014年 Facebook 提出了Flux 单向数据流架构,Redux 就是它的一种具体实现。Redux 于2015年面市,随即成为 Flux 架构下最流行的状态管理库。基于 Redux 已经形成了 UI 状态和服务数据缓存管理库的生态。目前 Redux 仍然非常的流行并且广泛使用。

[双语对照]react 状态管理的前世,今生和未来_第1张图片

远程缓存状态管理(原文Server Caching State)

In the early days of React, lots of state management boiled down to fetching data from APIs and caching it for use across the application. The community leaned heavily on libraries like Redux because there wasn't an easy, widely used way to manage just the server cache state.

在 React 的早期,大部分的状态管理做的事情就是从服务器取数据,然后缓存在本地,供前端应用使用。社区大量地使用类似 Redux 这样的状态管理,但没有出现一个被大众喜爱好用的缓存服务器状态的工具。

With the release of React Hooks, encapsulating logic into shared hooks became much easier and accessible. Libraries like SWR and React Query emerged to solve this problem specifically.

随着 React 推出了 Hooks,可以通过把通用逻辑封装在 hooks 中方便复用。于是类似 SWR 和 React Query 出现,专门用来解决远程状态管理的问题。

You might think, "Why have a separate library just for server caching state?". Well, caching is hard. Server caching state solves different problems than UI state. Here's a shortlist of some of the things these libraries handle for you:

你可能会想“为什么需要有一个专门用来做服务器数据缓存状态管理的工具库呢?”。因为:Caching is hard (缓存很难)。远程状态管理相较于 UI 状态管理要解决的是完全不同的问题,比如:

定时轮询数据 Polling on interval

选中时重新验证数据 Revalidation on focus

网络恢复后重新验证数据 Revalidation on network recovery

本地数据操作(用于实现乐观 UI) Local mutation (Optimistic UI)

错误的智能重试 Smart error retrying

分页和无限加载模式中的滚动定位 Pagination and scroll position recovery

Do you want to implement those yourself? Probably not.

你肯定不会想自己实现上面所有这些功能?

React Context

With v16.3, React Context gave us a first-party solution to share logic between components. This also prevented passing values down as props through multiple levels of nested components (i.e. "prop-drilling").

随着 16.3 版本的发布, React Context 直接提供组件之间共享逻辑的方案。这样我们就不用通过组件属性一层一层的传递到多层嵌套的组件(也称为:属性钻透 prop-drilling,参考 https://kentcdodds.com/blog/prop-drilling )。

React Context itself is not state management. It can, however, be paired with hooks like useReducer to become a state management solution. This combination solved UI state for many common use cases.

Context 本身并不是一种状态管理工具,但是通过和 useReducer 这个 hooks 组合就可以成为一种状态管理方案。这种组合的方案解决了很多 UI 状态管理的问题。

[双语对照]react 状态管理的前世,今生和未来_第2张图片

今生 present

In 2021, there are various ways to handle state management in React. As the community has grown to understand the different types of state, more granular libraries have been created solving very specific use cases.

在 2021 年涌现了大量的 React 状态管理库。随着社区对状态管理的理解越来越深入,许多不同颗粒度的库被创造出来解决特定的问题。

状态机

Let's consider a switch statement. If the value of state matches any case, the corresponding code runs. There's a finite set of cases. This is the most simple state machine – an explicit model of your state.

假设我们有一段 switch 代码,匹配到对应的值就执行对应的代码。这就是一个简单对状态准确定义的状态机。

// 伪代码
switch (state) { 

Case state === 'loading': 
// show loading spinner break; 

Case state === 'success': 
// show success message break; 

Default: 
// show error message 
}

Finite State Machines and Statecharts are fundamental Computer Science concepts, so this isn't anything React specific. You can turn useReducer into a state machine without any third-party libraries.

有限状态机和状态图是计算机领域中两个基础概念,并不是React中特有的东西。你在不引入任何第三方库的情况下,可把useRecuder转换成等价的状态机实现。

State Machines are well-adopted everywhere, including databases, electronics, cars, and more. As state management evolved in the React ecosystem, we realized these old ideas could solve modern state management issues. State Machines are most prevalent for solving form state.

状态机已经在各个领域广泛地使用,数据库、电子产品,汽车等等。随着状态机在 React 生态中的发展,我们发现这个老工具也能解决状态管理这个新问题。状态机特别适合解决表单状态管理。

With a Finite State Machine, you have a finite number of states your application or component could be in. In practice, State Machines help you uncover bugs as you're required to think through and define edge cases. For much more information on this, I'd recommend checking out the xState docs or watching this course. You can also visualize entire state machines online.

在一个有限状态机的模型里面,你的系统或者组件会归属到不同的状态。在实践中,状态机需要你思考和定义好边界情况,这样非常有助于你提前发现 bug。如果你想更多地了解状态机的话,我建议你看看 xState的文档(https://xstate.js.org/docs/)和 egghead 的这个教程(https://egghead.io/courses/introduction-to-state-machines-using-xstate),基于 xstate 定义的状态机还能被可视化。

Zustand, Recoil, Jotai, Valtio,学不动了!

Why do so many different libraries for React state management even exist?

为什么现在会有如此之多的状态管理库呢?

Let's consider Figma (or any other design tool). You have a toolbar of controls that affect other elements outside of its "local" state, or where the component is rendered.

假设我们在实现一个类似 Figma 的设计工具。你有一个工具栏,会影响应用中的其他状态,或者应用中组件是如何渲染。

[双语对照]react 状态管理的前世,今生和未来_第3张图片

As you can imagine, an application of this scale would require a complex state management solution. Performance and frame rate are critical for a good user experience here, so you want control over when & how to re-render. Unique use cases like this have led to lots of exploration in the state management space.

可以想象这样大规模地应用肯定需要一个复杂状态管理的解决方案。性能和应用的帧率对用户体验非常的重要,所以你会想控制在UI在何时用各种方式渲染。每种特殊的使用场景都会促进去发明一种新的状态管理的方式。

To summarize the differences between these libraries, let's hear from Daishi Kato:

用Daishi Kato的话来总结这些不同库的特点:

Valtio uses proxies to provide a mutation-style API

Valtio:使用 Proxy 提供一个可变数据风格 API 的状态管理工具。

Jotai is optimized for "computed values" and async actions

Jotai:为优化异步更新和“计算值”而生的状态管理

Zustand is a very thin library specifically focused on module state
Zustand:一个专注于状态模块化管理的轻量库。

Recoil is an experimental library using a data-flow graph

Recoil:基于数据流图的实验性质的状态管理库。

Having complex state doesn't necessarily mean you have to pull for a third-party library. You can start with React and JavaScript and see how far it takes you. If optimizing requires a state management library, you can track that metric (e.g. frame rate), measure it, and verify it solves a real problem.

有复杂的状态需要管理并不意味着你需要引入一个第三方的状态管理库。你可以试试裸用 React 看看能做到什么程度。如果遇到性能问题,需要引入一个第三方状态管理库,你在定义优化的数值目标(比如:帧率),然后测试下是不是解决了你的问题。

Don't choose one of these libraries unless there's an obvious need.

除非你真的需要,尽量不要随便引入状态管理库。

Immutable State

Another debate is mutable vs. immutable state. There are no right answers, just opinions. If you were doing state management with vanilla JavaScript, you'll likely have mutable state. You initialize a variable, and then later set it equal to some new value. There are entire debates on let vs. const.

状态管理的另外一个争论就是:可变状态和不可变状态。这个争论是没有正确答案的,只是两种不同的观点。如果你是直接用 javascript 来做状态管理的,你肯定会有很多状态:你初始化一个变量,然后再给它赋一个新值。其这种争论的本质就是用 let 还是 const。

Immutable state gained a lot of popularity with React. The immutable crowd argues that allowing your state management solution of choice to mutate state directly results in more bugs. The mutable crowd argues it's not worth the complex trade-off. Direct manipulation will always be less safe than indirect manipulation. It's a tradeoff between convenience and risk, which is up to you and your team.

不可变状态在 React 生态里面很流行。不可变状态的拥护者认为直接修改状态的数据非常容易引入 bug。可变状态的拥护者则认为,不可变带来的复杂度太高了。直接修改状态数据肯定是没有间接的方式安全。但是风险和便利之间应该如何平衡完全由你和你的团队自己决定。

Solutions like Immer allow you to write mutable code but execute it immutably. Fancy. The basic idea is you apply your changes to a draft state, which is a proxy of the current state. Once the mutations have completed Immer will produce the next state based on the changes to the draft state.

类似 Immer 让你通过写可变状态的方式实现不可变数据的状态管理。很炫酷。背后的思想就是通过对“草稿”状态直接赋值,“草稿”将这些操作再应用到当前的状态上去。

[双语对照]react 状态管理的前世,今生和未来_第4张图片

URL State

Let's say you're building an e-commerce website like Amazon. You search for React books and filter by 4+ stars. This state is persisted as query parameters and managed by the browser. When you refresh the page, you see the same list of products. You can share this URL with others and they also see the same results.

假设我们正在开发一个类似亚马逊的电子商务网站。你搜索了 4 星评价以上关于 React 的书,这搜索状态被持久化到URL地址中并被浏览器管理。当你重新刷新浏览器或者把地址分享给其他人,都能看到你的搜索结果。

[双语对照]react 状态管理的前世,今生和未来_第5张图片

Another interesting example of this is Nomad List. We can transform the browser URL state into a function of our data. Plus, we can make human-readable URLs (which Google prefers).

一个有趣的例子就是 Nomad list。我们通过一个函数根据页面数据生成一个URL地址 。这样就可以生成一个对人友好可读(对搜索引擎也友好)的 URL 地址。

[双语对照]react 状态管理的前世,今生和未来_第6张图片

未来 future

For large applications, it's possible a naive Context-based state management solutions (e.g. with useReducer) could have issues with excessive re-rendering.

在开发大型应用的时候,如果只用朴素的Reat Context 的方式(搭配 useReducer)来状态管理的话,很容易出现大量的多余的重新渲染。

When a context value changes, all components that useContext will re-render. This makes UI interactions feel slow and janky. If you can't visually notice it, you can use React Dev Tools to investigate re-rendering.

因为当一个 context 的值发生了改变,那么所有通过 useContext 使用这个 context 的组件都会重新渲染。这样会让我们的 UI 变慢变卡。如果察觉不到这个变化的话,可以试试用 React 的开发者工具更加细腻的观察组件的重渲染。

The React team has proposed a useSelectedContext hook to prevent performance issues with Context at scale. This RFC was introduced in July 2019 and progress has started as of January 2021 behind a feature flag. This hook allows you to select a "slice" of context and only re-render when that piece changes.

React团队已经在提议了一个新的 hook ,useSelectedContext用来解决 Context 使用过程中的问题。RFC 在 2019 年7 月提出,2021 年 1月就可以通过特性开关来试用。这个 hook 可以让你选择context 中的值部分改变,从而尽量减少不相关的组件的重渲染(译者注:类似 redux 里面的 map 函数)。

There are ways to work around re-rendering performance already (e.g. useMemo) but a first-party solution for Context is preferred.

虽然有很多方法能解决重渲染的性能问题(比如 useMemo),但是我们还是倾向使用 React 中原生的解决方案。

There's also a community library use ContextSelector, which takes a similar approach (demo). Jotai and Formik 3 use this under the hood. Having used SelectedContext as part of the React standard library will eliminate complexity and code size in external libraries, as well as provide more performant options by default.

很多社区的状态管理工具也是基于 ContextSelector (比如:这个例子)像Jotai 和 formik3 底层就是用的这个。如果使用 React 自带的selectedContext 不仅仅可降低代码量和复杂度,同时能带来性能提升。

In the longer-term future, React will automatically figure out which components to re-render ("auto-memoization").

在更遥远的未来, React 会自动分析是需要哪些组件需要重渲染(自动useMemo)

状态管理如何选择

This is not a comprehensive list. It's also open-source, so please open a PR if you disagree or if something is wrong. In general, lean on whatever empowers your developers and team. Happy with Redux? Stay there!

这个列表并不全面,但是随时接受大家提 PR 来更改和添加新的列表内容。总之一个原则就是,使用那些可以提高你团队效率的工具。如果喜欢用 redux,那就用 redux。

表单状态

开发者经验

学习热情

团队/项目规模

解决方案

初学者

useState

初学者

中小

专门的表单状态管理库 (Formik, Final Form)

初学者

中高

和你的 TL 讨论

中级

中小

专门的表单状态管理库 (Formik, Final Form)

高级工程师

状态机 例如 xState

高级工程师

状态机 例如 xState

高级工程师

状态机 例如 xState

UI 状态管理

开发者经验

学习热情

团队/项目规模

解决方案

初学者

useState

初学者

中小

useContext + useReducer

初学者

中高

和你的 TL 讨论

中级

中小

Redux Toolkit

高级工程师

useContext + useReducer

高级工程师

Jotai, Valtio

高级工程师

Recoil (如果在用GraphQL的话试试 Relay)

远程缓存状态

Regardless of experience or team size, both SWR and React Query are excellent solutions. You'll be happy with either. If you're using GraphQL, you probably already know about Apollo.

不用管你的团队规模和经验, SWR 和 React Query 都是很好的选择。你肯定会满意这两个库的;如果你用 Graphql 的话,那你肯定早就知道 Apollo 了。

State management in React has evolved massively over the past eight years. It's one of the most difficult, nuanced parts of building large web applications. Understanding the different types of state and their tradeoffs is crucial for making an informed decision. I hope this post has helped – thanks for reading.

React 的状态管理在最近的8年时间飞速发展。在构建 web 应用的时候如何选择一个状态管理工具是最头痛的问题。先了解各个类型状态管理工具的优缺点和要解决的问题,是正确选择他们的第一步。希望这篇文章能够帮助到你,谢谢阅读。

你可能感兴趣的:(java,区块链,编程语言,python,人工智能)