2021 年的 React 世界

930 阅读7分钟

2021 年,构建 React 应用的最佳方式是什么?自从 2016 年来,都发生了哪些变化?哪些是如今人们每天都在用的库?

我从 2016 年开始使用 React。我依然记得最初在海得拉巴市(Hyderabad)T-Hub 企业孵化器为一家初创公司工作时,讨论的是使用 Angular 还是 ReactJS 来开发应用程序。

在过去的几年中,React 本身发生了一些巨大的变化,React 生态同样也发生了很大的变化。

React 哲学:组件化的哲学

“React 哲学”的核心多年来并没有多大变化。仍然是关于单向数据流、属性(props)、状态(state)和 JS扩展语法(JSX)。像是决定哪些组件应该“拥有”数据,哪些应该只显示数据,这些将设计分解成组件的能力依然很重要。

Hooks vs Classes:现在我们更喜欢 Hooks

最近几年,React 最大的转变就是从类组件(classes)到 hooks,Hooks 是在 React 16.8 里加入的(2019年2月),很快就成为了人们编写 React 组建的标准方式。

最初,Hooks 看起来有点奇怪,尤其是你已经有过一段时间的编程经验。在函数调用之间看似保持着状态的变量看起来非常神奇。不过,它更多的是关于数组而不是魔法。

一旦你熟悉了 Hooks 的工作原理并且会使用 useState 了,下一个要克服的大障碍就是 useEffect 钩子了。

useEffect 是如何在函数组件中进行生命周期管理的答案。除了它的工作原理根本不像生命周期那样。 掌握 useEffect 的心智模型至关重要。 一旦你掌握了它,解决问题就会变得越来越容易。

2021 年度最佳 React 库

在库方面,社区的最爱多年来不断发生变化,并且还在持续着。

React 应用中的路由

React Router 仍然占据着主导位置(尽管名称如此,但实际上它并不是 React 的一部分)。React Router 是 React 中路由的标准库。 它支持在 React 应用程序中各个组件的视图间的导航,允许更改浏览器的 URL,并使 UI 视图与 URL 保持同步。

React 应用中的状态管理

Redux 仍然在很多应用中使用,我上次查看时覆盖范围在 30-50% 左右。官方新出的 Redux Toolkit 也很优秀。结合 Redux 的钩子使用,它能帮你减少大量的模版代码。如果你打算使用 Redux 的话,一定要了解一下。

不过,Redux 不像以前那样称得上业界标准了。越来越多的人们意识到 React 内置的状态管理对大多数使用场景已经足够了,尤其是对于简单应用来说。

还有一些新构建的库,可以来替代 Redux,我会在下面介绍几个。

MobX 大概是除了内置的 Context API 之外最流行的 Redux 替代品了。Redux 注重显式和函数性,而 MobX 则不同,它内部使用 ES6 的 Proxies 来侦测更改,因此更新可观测数据就像 使用 = 赋值运算符一样简单。

Context API

如果你的全局状态里包含一些很少改变的东西(当前用户、当前主题、当前语言等),你不需要一个专门的库来传递这些东西。

Context API 结合 useContext 非常适合传递由 useReducer 管理的简单全局状态。

React 16.3 中重新实现了 Context API。 原来的 contextType 已经过时了,关于“避免使用 Context 除非你是库维护者”的旧指南也已经删除一段时间了。 useContext 钩子让它变得非常好用。

数据获取(Data Fetching)

在数据获取方面,将所有内容放在 Redux 或全局存储中的策略也越来越少见。

react-query 在获取数据和管理加载/成功/错误状态方面做得很好。 它负责来维护跨组件间的全局数据缓存,让你不需要再考虑这些。

拿一个常见的场景,如有一组条目的列表页-详情页来说。你打开列表页,它会获取所有列表内容。目前为止一切正常。

正常来说,你大概会把数据保存在 Redux 之类的地方,以便打开某个条目的详情页时,这个条目的数据就已经是加载好的。

接着用户点击返回,又回到列表页,但你已经有了数据,所以你可以直接显示它。

一切工作正常,但存在一些边缘情况。 如果在用户加载完列表页和单击进入详情页这段时间里,有些数据过时了怎么办? 如果在他们在浏览详情页时,将一些新条目添加到列表里会怎样?

你该在什么时候重新获取数据?你又该如何来合并两种不同类型的数据——一个有可能替换整个列表的数组响应,和只替换一个列表项目的响应?在 Redux 中,reducer 负责处理这种情况,但大部分情况下你必须手动编写这些代码逻辑。

一旦你开始考虑分页,以及是否要缓存页面,是否要重新获取所有页面,或者其他什么,这会变得更加复杂。

我认为,所有这些东西都属于“客户端数据管理”的范畴,我们已经为此使用通用状态管理库很长时间了。 我们必须一遍又一遍地解决这类问题,或者我们直接忽略,希望不会出现问题,或者在出问题的时候再进行修复。

像 react-query 这样的库则以不同的方式解决问题。

它知道什么时候你要获取数据了,并且知道你想要用某个键(可能是items或嵌套的items[id])来缓存全局数据。 它还知道你有时会想要更新该数据,这是基于计时器,或者当用户离开应用程序并再次返回时等。

因为这些东西存储在一个全局可访问的缓存中,每个需要访问的组件都可以调用 useQuery('items', fetchItems) 来获取该数据,如果它不可用,则会自动获取。 它也可以处理空闲/加载/错误/成功状态。

它接受任何返回 Promise 的函数,因此它可以与 fetchaxios 或任何你想使用的数据获取器一起使用。

这就是我说它做了正确地逻辑抽象的意思——我们可以使用我们已经使用的任何东西来进行 HTTP 调用,react-query 来介入处理数据获取中经常重复的繁重工作的使用场景。

状态机是趋势

XState 是一个用于构建状态机的库,非常适合表示复杂的逻辑。 实际上,它们对于不那么复杂的逻辑也非常有用。 下次当您发现自己处理一堆布尔值或试图正确更新一堆变量时,试试 XState。 egghead.io 有一个由 Kyle Shevlin 编写的关于 XState 的不错的课程。

有一个名为 Robot 的替代方案,如果您想了解状态机如何发挥作用,我使用它编写了一个模态弹窗确认工作流的教程可能会有帮助。

打包工具

Webpack 仍然无处不在。 现在已经更新到第 5 版了。 配置语法相比 v2 或 v3 发生了很大变化。

现在大多数人使用 Create React App 来启动新的应用程序,这是很好的,它可以保护你免受 Webpack 的影响,除非你确实需要自定义。 默认配置就非常可靠。 如果您需要自定义内容,请查看 craco

表单

Formikreact-hook-form 现在似乎是最受欢迎的 ,随着 hook-form 蒸蒸日上。

Suspense

React 期待已久的 Suspense 功能……仍在等待中。 它现在在 React 中,您可以尝试一下,但它处于实验模式,不建议使用它构建生产代码。 API 仍然可以更改。

服务端组件

最新的进展是在服务端渲染的组件,以及围绕 React 的服务器端框架。 这些仍然是实验性的。 不过很酷,我期待这会改变生态系统。 查看 React 团队的官方 公告和演示视频 以了解更多信息。