React Labs:二月份研发进展 – 2024年2月
2024年2月15日 作者:Joseph Savona、Ricky Hanlon、Andrew Clark、Matt Carroll 和 Dan Abramov。
在React Labs的博文中,我们撰写关于积极研究和开发中的项目。自从我们上次更新以来,我们取得了显著进展,我们想分享我们的进展。
React 编译器
React 编译器不再是一个研究项目:该编译器现在为 instagram.com 提供生产环境支持,我们正在努力将其应用于Meta的其他平台,并准备首个开源版本。
正如我们在之前的博文中讨论的那样,当状态改变时,React *有时* 会进行过多的重新渲染。从React的早期开始,我们对这种情况的解决方案就是手动记忆化。在我们当前的API中,这意味着应用useMemo
、useCallback
和memo
API来手动调整React在状态更改时重新渲染的程度。但是手动记忆化是一种权衡。它使我们的代码混乱,容易出错,并且需要额外的工作来保持最新。
手动记忆化是一种合理的权衡,但我们并不满意。我们的愿景是让React在状态更改时*自动* 只重新渲染UI的正确部分,*而不会影响React的核心思维模型*。我们相信React的方法——UI作为状态的简单函数,使用标准的JavaScript值和习惯用法——是React易于被众多开发者接受的关键因素之一。这就是我们投资构建React优化编译器的理由。
由于其宽松的规则和动态特性,JavaScript 是一种众所周知的难以优化的语言。React 编译器能够通过模拟JavaScript的规则*和*“React的规则”来安全地编译代码。例如,React组件必须是幂等的——给定相同的输入返回相同的值——并且不能改变props或状态值。这些规则限制了开发人员可以执行的操作,并有助于为编译器优化创建一个安全空间。
当然,我们理解开发人员有时会稍微违反规则,我们的目标是使React编译器能够开箱即用地处理尽可能多的代码。编译器会尝试检测代码何时不严格遵循React的规则,并在安全的情况下编译代码,或者在不安全的情况下跳过编译。我们正在针对Meta庞大而多样的代码库进行测试,以帮助验证这种方法。
对于那些好奇如何确保其代码遵循React规则的开发人员,我们建议启用严格模式和配置React的ESLint插件。这些工具可以帮助捕获React代码中的细微错误,改进您应用程序的当前质量,并为即将推出的功能(如React编译器)做好准备。我们还在努力整合React规则的文档,并更新我们的ESLint插件,以帮助团队理解和应用这些规则,从而创建更强大的应用程序。
要查看编译器的实际运行情况,您可以查看我们去年秋天的演讲。在演讲时,我们获得了将React编译器应用于instagram.com的一个页面的早期实验数据。从那时起,我们将编译器应用于instagram.com的生产环境。我们还扩大了团队规模,以加快在Meta的其他平台上的推广和开源进程。我们对未来的发展方向感到兴奋,并在未来几个月内分享更多内容。
操作
我们之前分享过,我们正在探索使用服务器操作从客户端向服务器发送数据的解决方案,以便您可以执行数据库变异并实现表单。在开发服务器操作期间,我们扩展了这些API以支持客户端应用程序中的数据处理。
我们将这一更广泛的功能集合简称为“操作”。操作允许您将函数传递给DOM元素,例如<form/>
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
该action
函数可以同步或异步操作。您可以使用标准JavaScript在客户端定义它们,也可以使用'use server'
指令在服务器上定义它们。使用操作时,React将为您管理数据提交的生命周期,提供诸如useFormStatus
和useActionState
之类的钩子来访问表单操作的当前状态和响应。
默认情况下,操作会在一个过渡中提交,在操作处理过程中保持当前页面具有交互性。由于操作支持异步函数,我们还添加了在过渡中使用async/await
的能力。这允许你在像fetch
这样的异步请求开始时,使用过渡的isPending
状态显示等待中的UI,并在应用更新的整个过程中显示等待中的UI。
除了操作之外,我们还引入了一个名为useOptimistic
的功能,用于管理乐观状态更新。使用这个钩子,你可以应用临时更新,这些更新会在最终状态提交后自动回滚。对于操作,这允许你在客户端乐观地设置数据的最终状态(假设提交成功),并在从服务器接收数据时回滚到该值。它使用常规的async
/await
,因此无论你是在客户端使用fetch
,还是使用服务器端的服务器操作,它的工作方式都相同。
库作者可以在他们自己的组件中使用useTransition
实现自定义的action={fn}
属性。我们的目标是让库在设计其组件API时采用操作模式,从而为React开发者提供一致的体验。例如,如果你的库提供了一个<Calendar onSelect={eventHandler}>
组件,也考虑公开一个<Calendar selectAction={action}>
API。
虽然我们最初专注于服务器操作进行客户端-服务器数据传输,但我们对React的理念是在所有平台和环境中提供相同的编程模型。如果我们在客户端引入一个功能,我们力求使其也能在服务器端工作,反之亦然。这种理念使我们能够创建一套在应用程序运行位置无关的API,从而更容易升级到不同的环境。
操作现在已在Canary通道中可用,并将包含在下一个React版本中。
React Canary 的新功能
我们引入了React Canary,作为一种选择,以便在稳定语义版本发布之前,尽快采用单个新的稳定功能(只要其设计接近最终状态)。
Canary 改变了我们开发 React 的方式。以前,功能会在 Meta 内部私下研究和构建,因此用户只有在发布到稳定版时才会看到最终的完善产品。使用 Canary,我们正在社区的帮助下公开构建,以最终确定我们在 React Labs 博客系列中分享的功能。这意味着你可以更早地了解新功能,因为它们正在最终确定中,而不是在它们完成后。
React 服务器组件、资源加载、文档元数据和操作已全部进入 React Canary,并且我们已在 react.dev 上为这些功能添加了文档。
-
指令:
"use client"
和"use server"
是为全栈 React 框架设计的打包器功能。它们标记了两个环境之间的“分割点”:"use client"
指示打包器生成一个<script>
标签(类似于Astro Islands),而"use server"
告诉打包器生成一个 POST 端点(类似于tRPC Mutations)。它们共同允许你编写可重用的组件,这些组件将客户端交互性与相关的服务器端逻辑组合在一起。 -
文档元数据:我们添加了对在组件树中任何位置呈现
<title>
、<meta>
和元数据<link>
标签的内置支持。这些在所有环境中(包括完全客户端代码、SSR 和 RSC)的工作方式相同。这提供了对像React Helmet这样的库开创的功能的内置支持。 -
资源加载:我们将Suspense与样式表、字体和脚本等资源的加载生命周期集成在一起,以便React可以将它们考虑在内,以确定
<style>
、<link>
和<script>
等元素中的内容是否已准备好显示。我们还添加了新的资源加载API,如preload
和preinit
,以更好地控制资源何时加载和初始化。 -
操作:如上所述,我们添加了操作来管理从客户端向服务器发送数据。你可以将
action
添加到像<form/>
这样的元素中,使用useFormStatus
访问状态,使用useActionState
处理结果,并使用useOptimistic
乐观地更新UI。
由于所有这些功能都是协同工作的,因此很难单独在稳定通道中发布它们。在没有访问表单状态的补充钩子的情况下发布操作会限制操作的实际可用性。在没有集成服务器操作的情况下引入React服务器组件会使修改服务器上的数据变得复杂。
在我们能够将一组功能发布到稳定通道之前,我们需要确保它们能够协同工作,并且开发人员拥有在生产环境中使用它们所需的一切。React Canary 允许我们单独开发这些功能,并逐步发布稳定的 API,直到整个功能集完整为止。
React Canary 中当前的功能集已完成并准备发布。
React 的下一个主要版本
经过几年的迭代,react@canary
现在已准备好发布到 react@latest
。上述新增功能与您的应用运行的任何环境兼容,提供生产使用所需的一切。由于资源加载和文档元数据对某些应用来说可能是重大更改,因此 React 的下一个版本将是一个主要版本:React 19。
为发布做准备还需要做更多工作。在 React 19 中,我们还添加了长期以来备受期待的改进,这些改进需要重大更改,例如对 Web Components 的支持。我们现在的重点是完成这些更改,准备发布,完成新功能的文档,并发布包含内容的公告。
在接下来的几个月里,我们将分享更多关于 React 19 包含的所有内容、如何采用新的客户端功能以及如何构建对 React 服务器组件的支持的信息。
Offscreen(已重命名为 Activity)。
自从上次更新以来,我们将我们正在研究的一种功能从“Offscreen”重命名为“Activity”。名称“Offscreen”暗示它仅适用于不可见的应用程序部分,但在研究此功能时,我们意识到应用程序的某些部分可能是可见的但处于非活动状态,例如模态后面的内容。新名称更能反映将应用程序的某些部分标记为“活动”或“非活动”的行为。
Activity 仍在研究中,我们剩下的工作是最终确定向库开发者公开的原语。在我们专注于发布更完整的功能时,我们已经降低了这个领域的优先级。
除了此更新之外,我们的团队还在会议上发表演讲,并在播客中露面,以更详细地介绍我们的工作并解答问题。
-
Sathya Gunasekaran 在 React India 大会上讨论了 React 编译器
-
Dan Abramov 在 RemixConf 上发表了题为“来自另一个维度的 React”的演讲,探讨了 React 服务器组件和操作的另一种创建历史。
-
Dan Abramov 在 Changelog 的 JS Party 播客 上接受了关于 React 服务器组件的采访。
-
Matt Carroll 在 Front-End Fire 播客 上接受了采访,他讨论了 两个 React。
感谢 Lauren Tan、Sophie Alpert、Jason Bonta、Eli White 和 Sathya Gunasekaran 审阅这篇文章。
感谢您的阅读,并 在 React 大会上见!