距离 React 上次版本更新(v18.2)已经过去了600 多天。在这段时间里, ,其中不乏对 React 的期待、疑问和抱怨。那么,React 团队究竟在幕后忙些什么呢?本文将深入探讨 React 团队最近的研究进展,以期为大家揭示他们正在努力的方向。
React 编译器
React 编译器已经不再是单纯的研究项目,而是已经在 Instagram.com 的生产环境中得到了实际应用。React 团队正在努力将编译器推广至 Meta 的更多平台,并正在为首次开源发布做准备。
我们知道,React 在状态变化时有时会多次重新渲染。自 React 诞生之初,React 团队针对此类问题的解决方案一直是手动记忆化。在当前的 React API 中,这通常意味着使用
useMemo
、
useCallback
和
memo
API 来手动控制 React 在状态变化时的重新渲染频率。然而,手动记忆化并非理想的解决方案。它会使代码变得复杂和混乱,容易出错,并且需要投入额外的工作来保持其最新状态。
尽管手动记忆化是一个实用的折衷方案,但 React 团队对此并不满足。他们的愿景是,当状态发生变化时,React 能够自动、精确地重新渲染 UI 的相关部分,而无需牺牲 React 的核心设计原则。React 团队认为,React 的核心思想:将 UI 视为状态的函数,并利用标准的 JavaScript 值和习惯用法,这是 React 对如此多开发者具有吸引力的关键。为此, React 团队投入了大量精力来研发一个 React 的优化编译器。
考虑到 JavaScript 语言的动态性和规则灵活性,对其进行优化往往极具挑战性。然而,React 编译器通过模拟 JavaScript 的规则和「React 的规则」来安全地编译代码。例如,React 组件需遵循幂等性原则:在相同输入下应返回相同值,并且不得修改
props
或
state
值。这些规则不仅限制了开发者的操作范围,还为编译器优化提供了安全的空间。
当然,开发者有时会稍微违反一些规则,React 团队的目标是让 React 编译器能够尽可能多地在代码上直接运行。编译器会智能地检测代码是否严格遵循 React 的规则,如果确认安全,就会编译代码;若存在潜在风险,则会跳过编译。为了验证这一策略的有效性,目前正在使用 Meta 公司庞大且多样化的代码库进行测试。
对于希望确保代码遵循 React 规则的开发者,强烈推荐启用严格模式并配置 React 的 ESLint 插件。这些工具可以协助捕捉 React 代码中的潜在问题,提升应用质量,并为未来的功能(如 React 编译器)做好铺垫。React 团队正在完善 React 规则的官方文档,并更新 ESLint 插件,旨在帮助开发团队更好地理解和应用这些规则,从而构建更稳健的应用。
操作(Action)
React 团队正在探索通过「服务端操作」将客户端数据发送至服务端的解决方案,以便执行数据库变更和表单功能。在开发过程中,进一步扩展了这些 API,使其也支持仅在客户端应用中的数据处理。
为了简化这一综合功能集,将其统称为「操作」。通过「操作」,可以轻松地将函数传递给DOM元素,如
<form/>
标签:
<form action={search}>
<input name="query"/>
<button type="submit">Search</button>
</form>
action
函数可以同步或异步运行。可以选择在客户端使用标准 JavaScript 定义它们,或在服务端通过
'use server'
指令来实现。当使用操作时,React 将自动管理数据提交的生命周期,并提供如
useFormStatus
和
useFormState
等 Hook,使能够访问表单操作的当前状态和响应。
默认情况下,操作在转换过程中提交,确保在处理操作的同时,当前页面仍然保持交互性。由于操作支持异步函数,因此还增加了在转换过程中使用
async/await
的功能。这意味着,当发起异步请求(如
fetch
)时,可以通过转换的
isPending
状态来展示待处理的UI,并在应用更新期间持续显示该UI。
除了操作外,还推出了名为
useOptimistic
的新功能,用于
管理乐观状态更新
。此 Hook 允许应用临时更新,这些更新将在最终状态提交后自动回滚。
useOptimistic
利用了常规的
async/await
机制,因此无论是在客户端使用
fetch
,还是在服务端使用 Server Action,其工作方式都保持一致。
为了支持这一功能,库作者可以利用
useTransition
在自己的组件中实现自定义的
action={fn}
属性。鼓励库开发者在设计组件 API 时采纳操作模式,以确保为 React 开发者提供一致的使用体验。例如,如果库中包含一个
<Calendar onSelect={eventHandler}>
组件,建议也提供一个
<Calendar selectAction={action}>
API。
虽然 React 团队的初衷是专注于客户端与服务端之间的数据传输,通过服务端操作(Server Actions)来实现,但最终理念是为所有平台和环境提供统一的编程模型。因此,如果在客户端引入了新功能,会努力确保它也能在服务器端运行,反之亦然。这种统一的API设计使应用无论运行在何处都能保持一致性,从而简化了未来升级到不同环境的流程。
现在,操作(Actions)功能已在 Canary (预览版)中发布,并将随 React 的下一个版本正式推出。
React Canary (预览版)中的新功能
React Canary 的引入,提供了一种机制,允许在新功能的设计接近最终状态时,便能够采纳并使用这些稳定的特性,而无需等待它们被正式发布到稳定的版本中。
Canary 机制改变了开发 React 的方式。过去,新功能通常在 Meta 内部私下进行研究和构建,这意味着用户通常只能在功能完全成熟并被发布到稳定版本时才能体验到。然而,现在有了 Canary,React 团队选择在公开环境中与社区合作,共同完善在 React Labs 博客系列中分享的功能。这意味着,可以在功能仍在最终确定阶段时,就及时了解到这些新功能,而不是等到它们完全发布后。
目前, React Server Components 、 资源加载 、 文档元数据 和 操作 等特性已经成功登陆 React Canary,并且已经在 react.dev 上为这些新特性提供了详细的文档支持:
指令:
"use client"
和
"use server"
是全栈 React 框架中打包工具的关键功能,它们定义了客户端和服务端之间的「界限」。
"use client"
提示打包工具生成
<script>
标签(类似于 Astro Islands),而
"use server"
则指导打包工具创建 POST 端点(类似于 tRPC Mutations)。结合使用,它们让你能够构建可重用的组件,这些组件融合了客户端交互性和相关的服务端逻辑。
文档元数据:
现在为在组件树中的任何位置渲染
<title>
、
<meta>
和元数据
<link>
标签提供了内置支持。这种支持在所有环境中都是一致的,包括纯粹的客户端代码、服务端渲染(SSR)和 React Server Components(RSC)。这继承了由像React Helmet 这样的库开创的功能,并为其提供了官方的实现。
资源加载:
整合了
Suspense
与各种资源的加载生命周期,如样式表、字体和脚本。这使得 React 能够判断
< style>
、
<link>
和
<script>
等元素中的内容是否已准备就绪,从而进行适当的渲染。此外,新增了资源加载 API,如
preload
和
preinit
,为用户提供了更精细的控制,以确定资源应在何时加载和初始化。
操作:
如前所述,引入了操作(Actions)来管理从客户端到服务器的数据传输。可以将操作附加到
<form/>
等元素上,并使用
useFormStatus
来跟踪其状态,
useFormState
来处理结果。最重要的是,通过
useOptimistic
,可以实现乐观的UI更新,即在服务端确认之前预先显示预期的结果。
由于这些功能相互依赖,单独在稳定通道中发布它们将极具挑战性。没有互补的 Hook 来访问表单状态,发布操作(Actions)将削弱其实际效用。同时,不集成服务端操作(Server Actions)会导致在服务端修改数据变得繁琐。
为了确保这些功能能够协同工作,并为开发者在生产环境中提供完整的资源支持,必须在将它们发布到稳定通道之前进行充分的验证。React Canary 提供了逐个开发功能的便利,同时允许逐步发布稳定的 API,直至整个功能集完善。
目前,React Canary 中的功能集已经完备,并准备发布。
React 的下一个主要版本
经过几年的迭代,react@canary 现在已经准备好发布到 react@latest。上面提到的新功能将完美兼容任何应用环境,为生产使用提供了所需的一切。由于资源加载和文档元数据可能对某些应用构成破坏性更改,因此 React 的下一个版本将是一个主要版本: React 19 。
当然,发布前的准备工作仍在进行中。React 19 不仅包含了众多期待已久的功能增强,更引入了如 Web 组件支持等突破性的改进。目前,我们的重点在于完成这些功能的集成、做好发布前的最后准备、完善新功能的文档,并向大家公布版本更新的详细内容。
在接下来的几个月里,React 团队将分享更多关于 React 19 包含的内容、如何采用新的客户端功能以及如何为 React Server Components 构建支持的信息。
离线功能(更名为「活跃」)
,React 团队对一项正在研究的功能进行了重新命名,从原先的「离线」更名为「活跃」。原先的命名「离线」暗示此功能仅适用于应用中不可见的部分,但在深入研究过程中,我们意识到应用中的某些部分可能虽然可见,但并不活跃,例如模态窗口后面的内容。因此,新名称「 活跃 」更能准确地反映此功能的核心——标记应用的某些部分为「活跃」或「不活跃」。
目前,「 活跃 」功能仍在研究阶段,下一步工作是完善为库开发人员提供的基础功能。考虑到当前的重点是发布更完整的功能,暂时将这一领域的优先级降低。