首页 / 文章

React 19中的Actions实际应用:useActionState、use()函数以及编译器的相关废弃内容。

React 19中的actions功能让许多代码不再需要:表单处理函数、乐观更新、forwardRef以及手动记忆化。useActionState、use()以及编译器的相关改动也因此失去了用处。

发布者:REACTAPP.TOP阅读约 6 分钟1446 词

来源: React 19 Shipped Nine Months Ago. Most Teams Are Still Writing Code It Made Obsolete.

许多团队只是提升了 React 的版本号,其余部分则保持不变。他们多年前编写的加载状态指示、错误处理以及乐观更新逻辑依然存在于代码库中,因为升级并未破坏这些功能,只是让它们变得多余了。接下来将为您展示 React 19 现在已自动处理的手写代码。

反复出现的模式

打开 React 19 项目中的几乎任何表单组件,都会发现相同的结构。其中有三个状态变量,分别用于表示加载中、出错以及成功状态。还有一个异步提交处理函数,它会调用 e.preventDefault(),设置加载状态为开启,清除之前的错误信息,等待请求完成,在 try 块中将状态设为成功,在 catch 块中将错误信息复制到错误状态变量中,最后在 finally 块中关闭加载状态。

自从 React 受到欢迎以来,那种实现方式就一直被沿用,而且确实有效。但在 React 19 中已不再需要了。现在有一个钩子负责处理待处理状态、错误以及结果,还包括顺序请求的调度。由于升级并不会强制要求更改,大多数团队并未察觉到这一变化。

什么算是稳定的,什么不算

先简单列个对照表,因为有些文章会在功能尚未正式发布时就称其已可用。

在稳定的 React 19.x 中已具备的功能:

  • Actions 及基于它们的钩子:useActionState、useFormStatus 和 useOptimistic。
  • 用于在渲染过程中读取承诺值和上下文的 use() API。
  • ref 作为普通属性使用,这使得 forwardRef 成为过时功能。
  • 原生文档元数据:由组件渲染的 <title>、<meta> 和 <link> 标签。
  • React Compiler,已于2025年10月达到1.0版本,支持从React 17开始的各个版本。
  • 19.2版本新增的元素,如 <Activity> 和 useEffectEvent。
  • 在撰写本文时,<ViewTransition> 组件及Fragment Refs仍处于测试或实验阶段。凡是使用这些已发布功能的代码均视为过时,应查看实际安装版本的发布说明。

    Actions:异步状态的新模型

    React 19 的核心设计理念是 Action,这是一种传递给过渡过程的异步函数。React 会处理与之相关的一切:待处理状态、错误处理、乐观更新以及表单重置,这些都是过去团队需要手动编写的代码。

    useActionState、useFormStatus 和 useOptimistic 并非三个互不相关的功能,而是同一机制的三种表现形式。

    useActionState 替代了三状态标志模式

    无需再使用加载、错误和成功这三种状态,只需编写一个 Action 函数,该函数接收之前的状态和表单数据并返回新的状态。随后将此函数连同初始状态一起传递给 useActionState。该钩子会返回三样内容:当前状态、一个用于处理表单的函数,以及一个表示是否处于待处理状态的布尔值 isPending。

    该组件会执行三件简单的事:表单的action属性会直接接收返回的函数;当isPending为真时按钮会被禁用;任何消息都会从返回的状态中读取。这里没有加载状态,没有错误状态,没有try、catch或finally语句,没有preventDefault操作,也没有手动重置机制。

    将函数传递给action是经过深思熟虑的。HTML表单一直都有action属性,React 19重新采用了这一机制。这有助于实现渐进式增强,即即使没有JavaScript,表单也能提交数据,而React会在脚本加载后提升其功能表现。

    useFormStatus让按钮能够知晓其所关联的表单

    useFormStatus最实用的场景是创建可重复使用的提交按钮。在该钩子中,它会返回一个描述父表单的pending状态标志,且不会向下传递任何属性。当表单处于处理中时,按钮会自动禁用,其标签会变为“保存”之类的文字。只需将该组件放入任意表单中即可正常使用,从而避免了为满足这一常见需求而进行的属性层层传递。不过需要注意的是:该钩子会读取包裹该组件的表单的状态,因此它必须渲染在表单内部,而不能放在表单旁边。

    useOptimistic让即时反馈更易处理

    乐观更新会在服务器确认之前立即向用户展示预期结果,若请求失败则会自动修正。手动实现这种方式需要临时ID、待处理项的独立列表、合并逻辑以及错误分支中的回滚代码,很容易出现细微错误。

    使用 useOptimistic 后,你可以将真实列表以及一个用于描述如何添加带待处理标记项的简化 reducer 提供给该钩子。在表单的 action 中,调用它返回的设置函数,然后等待数据保存完成。界面会立即显示新项,待处理时可能会以较低的透明度呈现。当操作完成后,真实数据会替换掉乐观更新版本的数据,如果保存失败,React 会自动恢复到之前的状态,无需任何异常处理块或手动操作。

    use():条件性加载资源

    use() 是一种新的 API,可在渲染过程中读取资源,如 promise 或上下文。与其他所有钩子不同,它可以被条件性地调用。组件可以读取用户信息,当相关细节不可见时提前返回,之后再读取偏好设置。将整个组件结构包裹在带有备用内容的 Suspense 中,React 会暂停渲染直到数据到达。

    有一个重要限制:传递给 use() 的 promise 必须在多次渲染中保持稳定,因此应在组件外部创建这些 promise,或通过 React Query、SWR 等缓存层处理,甚至可以使用以 ID 为键的简单模块级映射。如果在每次渲染时都重新创建 promise,备用内容将永远显示在屏幕上。

    作为属性的 ref

    这一变更非常简单。函数组件现在可以将ref作为普通属性接收,因此无需用forwardRef包裹组件即可将其传递给底层输入元素。功能完全不变,只是减少了一个包裹层和一次导入操作。现有的forwardRef代码依然可用,因为这种废弃是逐步进行的且不会导致功能故障,但新组件不应再使用它。

    React编译器

    编译器是所有升级中最为低调的。它在构建时分析组件,并自动应用缓存机制——这些机制通常是开发人员手动用useMemo、useCallback和React.memo来实现,但方式往往不一致,或者干脆被忽略。你只需编写普通组件,编译器会自动正确地添加缓存功能。

    要尝试使用它,需安装 Babel 插件 babel-plugin-react-compiler 并将其添加到 Babel 配置的插件列表中。由于该插件同时支持 React 17 和 18,因此无需先升级 React 即可采用,这有助于那些因版本升级受阻但仍希望获得性能提升的团队。

    关于服务器组件的安全提示

    2026 年初,涉及服务拒绝和源代码泄露的安全警告影响了 react-server-dom-* 系列包,针对每个受支持的版本都发布了修复版本。如果您使用 React Server Components,请根据最新的安全警告检查所安装的版本,确保使用已修复或更新的版本,切勿仅凭记忆判断哪个版本是安全的。

    本周该做什么

    • 新表单:从一开始就使用 useActionState,定义一个操作,将其传递给钩子函数,然后从返回值中读取 isPending,完全无需手动创建标志位。
    • 现有处理函数:无需一次性重写所有内容。先挑选一个,将其转换为 Action 并查看其使用方式。可读性的提升通常十分明显,足以决定迁移的优先级。
    • 编译器:将其添加到你的构建配置中。这只是一个小改动,能够兼容现有代码且无需重写,因此它是 React 19 时代最容易实现且影响最广泛的改进。
    • 服务器组件:检查你的版本是否已包含相应的安全修复补丁。

    发布时,这些标题便吸引了大量关注。更重要的变化在于其背后:将 Actions 作为处理任何异步状态变化的标准模型,这悄然减少了 React 开发者每天需要编写的代码量。许多团队已经进行了升级,但相关代码仍在等待更新。

    相关阅读

  • 实用笔记:TypeScript 7 已发布快10倍的编译器——详情如下 —— 对“实用笔记:TypeScript 7 已发布快10倍的编译器——详情如下”中的内容进行详细讲解:适用于采用该模式的团队的契约、检查机制以及可直接插入的代码片段。
  • 让 React 重新渲染变得无趣:在记忆化之前先处理状态放置问题 —— 为何一次按键就会触发数十次渲染,以及如何通过状态放置、引用稳定性、上下文拆分和键值处理在使用 memo 或 useCallback 之前解决这个问题。
  • React依然占据优势,但JavaScript开发正在发生变化 — React在应用普及度上仍居首位,但如今围绕它的开发技术已包括TypeScript、服务端渲染、构建工具、性能优化以及人工智能。以下是接下来值得学习的内容。
  • 八种无需重写代码即可减少80%重新渲染次数的React渲染优化方法 — 首先进行性能分析,然后运用memo、useMemo、useCallback、过渡效果、列表虚拟化、代码分割以及精简选择器等技巧,从而提升大型React仪表板的运行速度。