React v18.0 更新内容

React v18.0

原文链接:https://zh-hans.reactjs.org/blog/2022/03/29/react-v18.html

2022 年 3 月 29 日,React 团队

React 18现在已经可以在npm上使用了!

在上一篇文章中,我们分享了 将您的应用升级到 React 18 的分步说明。 在这篇文章中,我们将概述 React 18 的新特性,以及它对未来的意义。

我们最新的主要版本包括开箱即用的改进,如自动批处理、startTransition 等新 API,以及支持 Suspense 的流式服务器端渲染。

React 18中的许多特性都是建立在我们新的并发渲染器之上的,这是一个幕后的变化,它开启了强大的新功能。Concurrent React是一个可选功能——只有当你使用并发特性时才启用——但我们认为它会对人们构建应用程序的方式产生重大影响。

我们花了数年时间研究和开发React中对并发的支持,并且我们格外小心地为现有用户提供了一个渐进的使用路径。去年夏天,我们成立了React 18工作组,收集社区专家的反馈,确保整个React生态系统的升级体验顺利进行。

如果你错过了,我们在React Conf 2021上分享了很多相关的内容:

下面是这个版本的完整概述,从并发渲染开始讲。

React Native用户注意:React 18将在 React Native中加入新的 React Native架构。更多信息,请参阅 React Conf 主题演讲.

什么是Concurrent React?

React 18 中最重要的新增功能是我们希望您永远不必去考虑的:并发性。 我们认为这对于应用程序的开发人员来讲基本上是一个正确的决定,尽管对于库的维护人员来讲这个情况可能就显得有点复杂了。

并发本身并不是一种新的特性。这其实是一个新的幕后机制,使React能够同时准备多个版本的UI。您可以将并发视为一个实现细节——它之所以有价值,是因为它解锁了一些功能。React在内部实现中使用了复杂的技术,比如优先级队列和多重缓存。但是你不会在我们的公共api中看到这些概念。

当我们设计 API 时,我们试图向开发人员隐藏实现细节。作为一名React开发者,你专注于 “你想要什么样的” 用户体验,,而 React 处理 如何 提供这种体验。所以我们不期望 React 开发人员知道并发是如何工作的。

然而,Concurrent React 本身的作用比它的实现细节更重要——它是对 React 核心渲染模型的基础更新。 因此,虽然了解并发的工作原理并不是特别重要,但在较高的层次上了解什么是并发可能是比较有意义的。

Concurrent React 的一个关键特性是渲染是可中断的。 当您第一次升级到 React 18 时,在添加任何并发功能之前,更新的呈现方式与之前版本的 React 相同——在一个单一的、不间断的同步事务中。 使用同步渲染时,一旦更新开始渲染,直到用户可以在屏幕上看到结果之前没有任何东西可以中断它。

在并发渲染中,情况并非总是如此。 React 可能会开始渲染更新,在中间暂停,然后再继续。它甚至可能完全放弃正在进行的渲染。React保证即使渲染中断,UI也会显示一致。为了做到这一点,它会等待 DOM 的变化到最后,直到完成对整个 DOM 树的评估。有了这个功能,React可以在不阻塞主线程的情况下在后台准备新屏幕显示。这意味着UI可以立即响应用户输入,即使是在大型渲染任务的中间,也可以创建流畅的用户体验。

另一个例子是可重用状态。Concurrent React可以从屏幕上删除一部分UI,然后在需要重用之前状态时将它们添加回来。例如,当用户从一个屏幕上移开并返回时,React 应该能够将前一个屏幕恢复到与之前相同的状态。在即将到来的小改动中,我们计划添加一个名为<Offscreen>的新组件来实现这个模式。类似地,你将能够使用Offscreen在后台准备新的UI,以便在用户显示它之前它就已经准备好了。

并发渲染是 React 中一个强大的新工具,我们的大多数新功能都是为了利用它而构建的,包括 Suspense、过渡和流式服务器渲染。但是React 18只是我们构建此新基础目标上的一个起点而已。(备注:换句话说以后 React 的升级也会围绕着这个特性展开)

渐进的并发特性

从技术上讲,并发渲染是一个突破性的变化。 因为并发渲染是可中断的,所以启用它时组件的行为会略有不同。

在我们的测试中,我们已经将数千个组件升级到了 React 18。我们发现几乎所有现有组件都“可以正常工作”并发渲染,没有任何更改。但是,其中一些可能需要一些额外的迁移工作。尽管这些变化通常很小,并且您仍然能够按照自己的步调进行更改。React 18中的新渲染行为只会在你的一部分应用中使用新特性时启用

整体升级策略是让您的应用程序在 React 18 上运行,而不会破坏现有代码。然后,您可以按照自己的步调逐渐开始添加并发功能。您可以使用 <StrictMode> 来帮助你在开发过程中发现与并发相关的错误。严格模式不会影响生产行为,但在开发过程中它会记录额外的警告和预期是幂等的双重调用函数。它不会捕获所有内容,但它可以有效地防止最常见的错误类型。

升级到 React 18 后,您将能够立即开始使用并发功能。例如,您可以在屏幕之间导航时使用 startTransition ,从而不会阻塞用户输入。 或者使用DeferredValue 来限流昂贵的重渲染。

但是,从长远来看,我们希望您向应用程序添加并发的主要方式是使用支持并发的库或框架。在大多数情况下,您不会直接与并发 API 交互。例如,比起开发人员手动的在导航到一个新屏幕时调用startTransition,更多情况下是路由器库自动在startTransition中包装导航。

当你将库升级为并发库时,在兼容性上面可能需要一些时间。我们提供了新的 API,使库更容易利用并发特性。同时,我们正在逐步迁移 React 生态系统的过程中,请给我们多一点时间和耐心。

欲了解更多信息,请参阅我们之前的文章:如何升级到React 18

数据框架中的Suspense

在React 18中,你可以开始在Relay、Next.js、Hydrogen或Remix等框架中使用Suspense 来获取数据。使用Suspense 进行临时数据抓取在技术上是可行的,但仍不推荐作为最佳实践方案。

在将来,我们可能会更新出更多的原始语法来帮助你更容易的使用Suspense 来获取数据,这样一来你也许就不再需要使用上面所提到的那些框架了。然而,当 Suspense 深度集成到您的应用程序架构中时,它的效果最好,例如集成到:您的路由器、您的数据层和您的服务器渲染环境。因此从长远来看,我们预计库和框架将在 React 生态系统中发挥至关重要的作用。

与之前的 React 版本一样,您还可以使用 Suspense 在客户端上通过 React.lazy 进行代码拆分。但我们对 Suspense 的期望始终不仅仅局限于加载代码层面——我们的目标是通过扩展对 Suspense 的支持,最终能够达到相同的声明性 Suspense 回退可以处理任何异步操作(包括加载代码、数据、图像等)。

服务器组件仍在开发中)

服务器组件 是一项即将推出的功能,允许开发人员构建应用程序 跨越服务器和客户端,将客户端应用程序的丰富交互性与传统服务器渲染的改进性能相结合。服务器组件并不是与 Concurrent React 耦合的,但它的设计是为了配合 Suspense 和流式服务器渲染等并发功能更好的工作。

服务器组件仍处于试验阶段,但我们希望在 18.x 次要版本中发布初始版本。与此同时,我们正在与像Next.js、Hydrogen和Remix这样的框架合作,以推进这个提案,并为广泛采用做好准备。

React 18 的新功能

新功能:自动批处理

批处理是 React 将多个状态更新分组到一个重渲染中以获得更好的性能。如果没有自动批处理,我们只能在 React 事件处理程序中批处理更新。默认情况下,Promise的状态更新、setTimeout、事件处理程序或任何其他事件都没有在 React 中批处理。使用自动批处理,这些更新将自动批处理:

// 之前:只对 React 事件进行批处理。
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React 将渲染两次,状态每更新一次就会渲染一次(无批处理)
}, 1000);

// 之后:timeouts时、promises、本地事件处理程序或任何其他事件内的更新被批处理。
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React 只会在最后重新渲染一次(这就是批处理!)
}, 1000);

要了解更多信息,请参阅这篇文章在React 18中自动批处理获取更少的渲染

新功能:Transitions

过渡是 React 中的一个新概念,用于区分紧急更新和非紧急更新。

  • 紧急更新反映了直接的交互,例如输入、点击、按下等等。
  • 过渡更新用于过渡UI,将一个视图过渡到另一个视图。

输入、点击或按下等紧急更新需要立即响应,以便于符合我们对物理对象行为方式的直觉。否则他们会觉得“不对劲”。 然而,过渡更新则有所不同,因为用户并不希望在屏幕上看到两个视图切换时的每个中间值。

例如,当您在下拉列表中选择过滤器时,您希望过滤器按钮本身在您单击时立即响应。然而,实际的结果可能是会分别进行过渡。轻微的延迟是察觉不到的,而且常常是预料之中的。如果在渲染结果之前再次更改过滤器,那么您只关心查看最新的结果。

通常,为了获得最佳用户体验,单个用户输入应该既有紧急更新也有非紧急更新。你可以在输入事件中使用 startTransition API 来通知 React 哪些更新是紧急更新,哪些是“过渡更新”:

import {startTransition} from 'react';

// Urgent: Show what was typed
// 紧急:显示输入的内容
setInputValue(input);

// Mark any state updates inside as transitions
// 将内部的任何状态更新标记为过渡更新
startTransition(() => {
  // Transition: Show the results
  // Transition: 显示结果
  setSearchQuery(input);
});

包装在 startTransition 中的更新被视为非紧急更新,如果出现更紧急的更新(如点击或按键),则会被中断。如果过渡更新被用户打断(例如,通过连续输入多个字符),React 将丢弃未完成的陈旧渲染工作并仅渲染最新更新。

  • useTransition:一个开始过渡更新的 hook,包含一个跟踪 pending 状态的值。
  • startTransition:一种在无法使用 hook 时要进行过渡更新的替代方法。

Transitions 将选择并发渲染,这意味着允许更新被中断。如果内容重新挂起,过渡也会告知 React 继续显示当前内容,同时在后台渲染过渡内容(更多信息请参阅suspension RFC)。

在文档中查看过渡

新的Suspense功能

如果组件树的一部分尚未准备好显示,Suspense 允许您以声明方式指定其加载状态:

<Suspense fallback={<Spinner />}>
  <Comments />
</Suspense>

Suspense 使“UI 加载状态”成为了 React 编程模型中第一级别的声明性概念。 这让我们可以在它之上构建更高级别的功能。

几年前,我们推出了 Suspense 的限量版。但是在当时唯一支持的就是用React.lazy 进行代码拆分,并且当时根本不支持服务器渲染。

在 React 18 中,我们在服务器上添加了对 Suspense 的支持,并使用并发渲染特性扩展了它的功能。

React 18 中的 Suspense 与transition API 结合使用时效果最佳。如果你在过渡期间使用Suspense ,React会阻止已经可见的内容被回退替换。相反,React 还会延迟渲染,直到加载了足够的数据以防止出现错误的加载状态。

更多信息,请参见RFC React 18中的Suspense

新的客户端和服务器渲染APIs

在这个版本中,我们借此机会重新设计了我们为在客户端和服务器上公开的 API。这些更改允许用户在升级到 React 18 中的新 API 时继续使用 React 17 模式下的旧 API。

React DOM 客户端

这些新的 API 现在从 react-dom/client 导出:

  • createRoot:创建用以“渲染”或“卸载”的新根部方法。 使用它来代替 ReactDOM.render。 没有它,React 18 中的新功能就无法工作。
  • hydrateRoot:进行服务器端渲染时的一个新方法,使用这个方法联合新的 React DOM 服务器 API 来替代 ReactDOM.hydrate, 没有它,React 18 中的新功能就无法工作。

createRoothydraRoot 都接受一个名为 onRecoverableError 的新选项,以便于你希望在 React 渲染期间发生的错误时,收到恢复或日志记录的通知。默认情况下,React会使用reportError ,但在旧浏览器中则会使用console.error。

参阅React DOM 客户端文档

React DOM 服务器端

这些新的api现在从react-dom/server导出,并完全支持服务器上的Suspense 流:

  • renderToPipeableStream: 用于 Node 环境中的流式传输。
  • renderToReadableStream:适用于现代比较新的运行时环境,例如 Deno 和 Cloudflare worker。

现有的renderToString方法仍然有效,但不推荐使用。

参见React DOM 服务器端文档

新的严格模式行为

在未来,我们希望增加一个功能,允许React在保持状态的情况下添加和删除UI的部分。例如,当用户从一个屏幕上移开并返回时,React 应该能够立即显示上一个屏幕。为了做到这一点,React会像以前一样使用相同的组件状态卸载和重新挂载树。

这一特性将使React应用的开箱即用性能更好,但要求组件能够适应多次加载和销毁。大多数效果无需任何更改即可工作,但有些效果假定它们只能够安装或销毁一次。

为了帮助解决这些问题,React 18 为严格模式引入了一个新的仅限开发的检查。每当第一次安装组件时,此新检查将自动卸载并重新安装每个组件,并在第二次安装时恢复先前的状态。

在此更改之前,React 会挂载组件并创建效果:

* React mounts the component.
  * Layout effects are created.
  * Effects are created.

使用 React 18 中的严格模式,React 将在开发模式下模拟卸载和重新安装组件:

* React mounts the component.
  * Layout effects are created.
  * Effects are created.
* React simulates unmounting the component.
  * Layout effects are destroyed.
  * Effects are destroyed.
* React simulates mounting the component with the previous state.
  * Layout effects are created.
  * Effects are created.

在这里查看确保状态复用的相关文档

新的 Hooks

useId

useId 是一个新的 hook,用于在客户端和服务器上生成唯一 ID,同时避免了服务器端渲染时的 id 不匹配问题。它主要用于一些集成有可访问性 API 的组件库,这些组件库可能要求唯一的 ID。这解决了 React 17 以及更低版本中所存在的问题,但在 React 18 中显得更为重要,因为新的流式服务端渲染器需要无序的渲染 HTML。参阅文档.

useTransition

useTransitionstartTransition 让你将一些状态更新标记为不紧急。默认情况下,其他状态更新被认为是紧急的。React 将允许紧急状态更新(例如,更新文本输入)中断非紧急状态更新(例如,呈现搜索结果列表)。参阅文档

useDeferredValue

useDeferredValue 允许您推迟重新渲染树时的非紧急部分。它类似于防抖,但与之相比还是有一些优点。没有固定的时间延迟,因此 React 渲染首屏后会立即尝试延迟渲染。延迟渲染是可中断的,不会阻塞用户输入。参阅文档.

useSyncExternalStore

useSyncExternalStore 是一个新的 hook,它允许外部存储通过强制对存储的更新同步来支持并发读取。它在实现对外部数据源的订阅时取消了对 useEffect 的依赖,并且在使用 React 其他的外部状态管理库时推荐使用它。参阅文档.

注意:

useSyncExternalStore 一般是用于供第三方库来使用的,而不是用于开发者的应用程序的业务代码中。

useInsertionEffect

useInsertionEffect 是一个新的hook,它允许 CSS-in-JS 库解决在渲染中注入样式的性能问题。除非您已经构建了 CSS-in-JS 库,否则我们不希望您使用它。这个hook会在 DOM 发生变化之后,但在读取新的布局效果之前运行。这解决了 React 17 以及更低版本中已经存在的问题,但在 React 18 中显得更为重要,因为React在并发渲染期间会将执行权交给浏览器,这就给了它重新计算布局的机会。参阅文档.

注意:

useInsertionEffect一般是用于供第三方库来使用的,而不是用于开发者的应用程序的业务代码中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值