距离 React 最近一次版本更新已经过去了 8 个多月。那最近 React 都在忙些啥呢?下面就来看看 React 团队最近正在研究的事,以及取得的进展!
概览:
- React Server Components
- 资源加载
- 文档元数据
- 离屏渲染
- Transition Tracing
React Server Components
React Server Components(RSC,服务端组件)是由 React 团队设计的一种新的应用架构。
React 团队正在引入一种新的组件——服务器组件,它提前运行并且被排除在 JavaScript 包之外。服务器组件可以在构建期间运行,从文件系统读取或获取静态内容。它们还可以在服务端运行,无需构建 API 即可访问数据层。可以通过 props 将数据从服务端组件传递到浏览器中的交互式客户端组件。
RSC 将以服务端为中心的多页面应用的简单“请求/响应”心智模型与以客户端为中心的单页应用的无缝交互相结合,提供了两全其美的体验。
自上次更新以来,React 团队合并了 React 服务端组件 RFC 以批准该提案。通过 [React Server Module Conventions](React Server Module Conventions) 提案解决了悬而未决的问题,并与合作伙伴达成共识以遵循“use client”的约定。这些文档还充当 RSC 兼容实现应支持的规范。
最大的变化就是引入了 async / await 作为从服务端组件获取数据的主要方式。 除此之外,还计划通过引入一个名为 use
的新 Hook 来支持从客户端加载数据,该 Hook 用于解包 Promises。虽然不能在仅客户端应用的任意组件中支持 async / await
,但计划在构建仅客户端应用时添加对它的支持,类似于 RSC 应用的结构。
现在已经解决了数据获取的问题,并正在探索另一个方向:将数据从客户端发送到服务器,以便可以执行数据库突变和实现表单。通过让跨服务端/客户端边界传递服务端操作(Server Action)函数来实现这一点,然后客户端可以调用这些函数,从而提供无缝的 RPC。Server Actions 还在 JavaScript 加载之前提供逐步增强的表单。
React 服务端组件已经在 Next.js 应用路由中发布。这展示了一个真正将 RSC 视为原语的路由的深度集成,但这并不是构建与 RSC 兼容的路由和框架的唯一方法。RSC 规范和实现提供的特性有明显的区别。React 服务端组件是指跨兼容React框架工作的组件规范。
React 团队通常建议使用现有框架,但如果需要构建自己的自定义框架,也是可以的。构建自己的 RSC 兼容框架并不容易,因为需要深度构建工具集成。当前一代的构建工具非常适合在客户端上使用,但它们在设计时并没有为在服务端和客户端之间拆分单个模块图提供一流的支持。这就是为什么 React 团队现在直接与构建工具开发人员合作以获得内置的 RSC。
资源加载
Suspense 允许指定在组件的数据或代码仍在加载时在屏幕上显示什么内容。这使用户可以在页面加载时以及加载更多数据和代码的路由导航期间逐步看到更多内容。但是,从用户的角度来看,在考虑新内容是否准备就绪时,数据加载和渲染并不能说明全部。默认情况下,浏览器独立加载样式表、字体和图像,这可能导致 UI 跳转和连续的布局转换。
React 团队正在努力将 Suspense 与样式表、字体和图像的加载生命周期完全集成,以便 React 将它们考虑在内,以确定内容是否已准备好显示。在不改变编写 React 组件的方式的情况下,更新将以更加连贯的方式进行。作为一种优化。,还将提供一种手动方式来直接从组件中预加载字体等资源。
文档元数据
应用中的不同页面可能具有不同的元数据,例如 <title> 标签、description 和其他特定于此页面的 <meta> 标签。从维护的角度来看,将此信息放在该页面的 React 组件中会更具可扩展性。但是,此元数据的 HTML 标签需要位于文档的 <head> 中,该文档通常在应用的最根组件中。
现在有两种方法可以解决这个问题:
- 渲染一个特殊的第三方组件,该组件将 <title>、<meta> 和其中的其他标签移动到文档的 <head> 中。这适用于主流浏览器,但有许多客户端不运行客户端 JavaScript,例如 Open Graph 解析器,因此该技术并不普遍适用。
- 将页面分为两部分进行服务端渲染。首先,渲染主要内容并收集所有此类标签。然后使用这些标签渲染 <head> 。最后,<head> 和主要内容被发送到浏览端。这种方法是可行的,但这样就不能使用 React 18 中的流式服务端渲染了,因为必须等待所有内容渲染完毕才能发送 <head>。
这就是为什么 React 要 在组件树中的任何位置添加内置支持来渲染 <title>、<meta> 和元数据 <link> 标签。它在所有环境中都以相同的方式工作,包括完全的客户端代码、SSR,以及未来的 RSC。
React 优化编译器
React 团队一直在积极迭代 React Forget 的设计,这是一个针对 React 的优化编译器。之前曾将其称为“自动记忆编译器”,这在某种意义上是正确的。但是构建编译器帮助 React 团队更深入地理解了 React 的编程模型。理解 React Forget 的更好方法是将其作为一个自动响应式编译器。
React 的核心思想是开发人员将 UI 定义为当前状态的函数。使用普通的 JavaScript 值:数字、字符串、数组、对象,并使用标准的 JavaScript 语法:if/else、for 等描述组件逻辑。心智模型是 React 将在应用状态更改时重新渲染。这种简单的心智模型和与 JavaScript 语义保持接近是 React 编程模型中的一个重要原则。
问题是 React 有时会响应过度:它会重新渲染太多。例如,在 JavaScript 中没有直接的方法来比较两个对象或数组是否相等(具有相同的键和值),因此在每次渲染时创建一个新的对象或数组可能会导致 React 执行比它严格需要的更多的工作。这意味着开发人员必须明确记忆组件,以免对更改响应过度。
React Forget 的目标是确保 React 应用在默认情况下具有适量的响应:应用仅在状态值发生有意义的变化时才重新渲染。从实现的角度来看,这意味着自动记忆,但 React 团队认为响应式框架是理解 React 和 Forget 的更好方式。React 目前会在对象标识更改时重新渲染。有了 Forget,React 会在语义值发生变化时才重新渲染——但不会产生深度比较的运行时成本。
进展而言,自上次更新以来,React 团队对编译器的设计进行了大量迭代,以与这种自动响应式方法保持一致,并纳入内部使用编译器的反馈。在去年年底开始对编译器进行一些重大重构之后,现在已经开始在 Meta 部分生产中使用编译器。一旦在生产中证明了它的价值,就计划将其开源。
离屏渲染
离屏渲染是 React 即将推出的一项功能,用于在后台渲染屏幕而无需额外的性能开销。可以将其视为 CSS 属性 content-visibility
的一个版本,它不仅适用于 DOM 元素,也适用于 React 组件。在研究过程中,发现了各种用例:
- 路由可以在后台预渲染页面,以便当用户导航到该页面时,页面立即可用;
- 选项卡切换组件可以保留隐藏选项卡的状态,因此用户可以在它们之间切换而不会丢失进度。
- 虚拟列表组件可以在可见窗口上方和下方预渲染额外的行。
- 打开模态框或弹出窗口时,可以将应用的其余部分置于“后台”模式,以便除模式之外的所有内容都禁用事件和更新。
大多数 React 开发人员不会直接与 React 屏幕外的 API 交互。相反,离屏渲染将被集成到路由和 UI 库中,使用这些库的开发人员将自动受益,而无需额外的工作。
这个功能可以让我们在不改变编写组件的方式的情况下在屏幕外渲染任何 React 树。当一个组件在屏幕外渲染时,它实际上并没有挂载,直到组件可见——它的 effect 不会被触发。离屏渲染的一个关键特性就是可以在不丢失其状态的情况下切换组件的可见性。
自上次更新以来,React 团队在 Android 和 iOS 上的 React Native 应用中测试了 Meta 内部预渲染的实验版本,并取得了积极的性能结果。除此之外,还改进了离屏渲染与 Suspense 的工作方式——在离屏树内暂停不会触发 Suspense 回退。剩下的工作就涉及完成向库开发人员公开的原语。希望在今年晚些时候发布一个 RFC,以及一个用于测试和反馈的实验性 API。
Transition Tracing
Transition Tracing API 可以检测 React Transitions 何时变慢并调查它们变慢的原因。在上次更新后,React 团队完成了 API 的初始设计并发布了 RFC,基本能力也已经实现,该项目目前处于搁置状态。欢迎对 RFC 进行反馈,并期待恢复其开发,为 React 提供更好的性能测量工具。这对于构建在基于 React Transitions 的路由特别有用,比如 Next.js 应用路由。
参考:https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023