- React 19 中的新增功能
- Actions
- 新钩子:useActionState
- React DOM:<form> action
- React DOM:新钩子:useFormStatus
- 新钩子:useOptimistic
- 新的 API:use
- React 服务器组件
- React 19 的改进
- ref 作为 prop
- 水合错误的差异
- <Context>作为提供者
- refs 的清理函数
- useDeferredValue 初始值
- 对文档元数据的支持
- 支持样式表
- 支持异步脚本
- 支持预加载资源
- 与第三方脚本和扩展的兼容性
- 更好的错误报告
- 支持自定义元素
- 如何升级
React 19 Beta 现已在 npm 上提供!
注意:此 Beta 版本发布是为了让库为 React 19 做好准备。应用程序开发者应该升级到 18.3.0 并等待 React 19 稳定版,因为我们将与库合作并根据反馈进行更改。
在我们的 React 19 Beta 升级指南 中,我们分享了将您的应用升级到 React 19 Beta 的逐步说明。在这篇文章中,我们将概述 React 19 中的新功能以及您如何采用它们。
React 19 中的新增功能
Actions
在 React 应用中一个常见的用例是执行数据变更,然后相应地更新状态。例如,当用户提交表单以更改他们的姓名时,你将发出 API 请求,然后处理响应。在过去,你需要手动处理待处理状态、错误、乐观更新和顺序请求。
例如,你可以在 useState 中处理待处理和错误状态:
// Before Actions
function UpdateName({}) {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, setIsPending] = useState(false);
const handleSubmit = async () => {
setIsPending(true);
const error = await updateName(name);
setIsPending(false);
if (error) {
setError(error);
return;
}
redirect("/path");
};
return (
<div>
<input value={name} onChange={(event) => setName(event.target.value)} />
<button onClick={handleSubmit} disabled={isPending}>
Update
</button>
{error && <p>{error}</p>}
</div>
);
}
在 React 19 中,我们正在添加对在转换中使用异步函数的支持,以自动处理待处理状态、错误、表单和乐观更新。
例如,你可以使用useTransition处理待处理状态:
// Using pending state from Actions
function UpdateName({}) {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();
const handleSubmit = async () => {
startTransition(async () => {
const error = await updateName(name);
if (error) {
setError(error);
return;
}
redirect("/path");
})
};
return (
<div>
<input value={name} onChange={(event) => setName(event.target.value)} />
<button onClick={handleSubmit} disabled={isPending}>
Update
</button>
{error && <p>{error}</p>}
</div>
);
}
异步转换将立即将isPending状态设置为true,进行异步请求,并在任何转换后将isPending切换为fals。这使你可以在数据更改时保持当前 UI 的响应性和交互性。
按照惯例,使用异步过渡的功能通常被称为
Actions。
Actions会自动帮助你提交数据:
- Pending 状态:Actions 提供一个从请求开始时就开始的 pending 状态,并在最终状态更新提交时自动重置。
- 乐观更新:Actions 支持新的
useOptimistichook,因此你可以在请求提交时向用户显示即时反馈。- 错误处理:Actions 提供错误处理,因此你可以在请求失败时显示错误边界,并自动将乐观更新恢复到其原始值。
- 表单:
<form>元素现在支持将函数传递给action和formActionprops。将函数传递给actionprops 会默认使用Actions,并在提交后自动重置表单。
在React 19中,基于 Actions,引入了useOptimistic来管理乐观更新,还有一个新的 hook React.useActionState来处理 Actions 的常见情况。在react-dom中,我们正在添加<form> Actions 来自动管理表单,并且添加useFormStatus来支持表单中 Actions 的常见情况。
在 React 19 中,上述示例可以简化为:
// Using <form> Actions and useActionState
function ChangeName({ name, setName }) {
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
return error;
}
redirect("/path");
}
);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</form>
);
}
在下一节中,我们将详细介绍 React 19 中的每个新 Action 功能。
新钩子:useActionState
为了使操作更容易处理常见情况,我们添加了一个名为useActionState的新钩子:
const [error, submitAction, isPending] = useActionState(async (previousState, newName) => {
const {error} = await updateName(newName);
if (!error) {
// You can return any result of the action.
// Here, we return only the error.
return error;
}
// handle success
});
useActionState接受一个函数(Action),并返回一个包装后的 Action 以供调用。这在 Actions 组合时非常有效。当调用包装后的 Action 时,useActionState 将返回 Action 的最后结果作为数据,并返回 Action 的挂起状态作为 pending。
React.useActionState之前在Canary版本中被称为ReactDOM.useFormState,但我们已将其重命名并弃用useFormState。详细信息请参见#28491。
更多信息,请参阅useActionState文档。
React DOM:<form> action
Actions也集成了 React 19 新的 <form>功能,用于 react-dom。我们支持将函数传递为<form>、<input>和 <button> 元素的 action 和 formAction 属性,以便自动提交包含 Actions 的表单。
<form action={actionFunction}>
当<form> Action 成功时,React 会自动重置不受控制组件的表单。如果需要<form>手动重置,可以调用新的requestFormResetReact DOM API。
有关更多信息,请参阅react-dom文档中的<form>、<input>和<button>。
React DOM:新钩子:useFormStatus
在设计系统中,通常会编写设计组件,这些组件需要访问有关它们所在的<form>的信息,而无需将props传递给组件。这可以通过Context来实现,但为了使常见情况更容易处理,我们添加了一个新的 hook useFormStatus:
import {useFormStatus} from 'react-dom';
function DesignButton() {
const {pending} = useFormStatus();
return <button type="submit" disabled={pending} />
}
useFormStatus读取父级的状态<form>,就像表单是上下文提供者一样。
更多信息,请参阅 react-dom 的文档 useFormStatus。
新钩子:useOptimistic
在执行数据变更时,另一个常见的用户界面模式是在异步请求进行时乐观地显示最终状态。在 React 19 中,我们添加了一个名为useOptimistic的新钩子,以使这更容易:
function ChangeName({currentName, onUpdateName}) {
const [optimisticName, setOptimisticName] = useOptimistic(currentName);
const submitAction = async formData => {
const newName = formData.get("name");
setOptimisticName(newName);
const updatedName = await updateName(newName);
onUpdateName(updatedName);
};
return (
<form action={submitAction}>
<p>Your name is: {optimisticName}</p>
<p>
<label>Change Name:</label>
<input
type="text"
name="name"
disabled={currentName !== optimisticName}
/>
</p>
</form>
);
}
使用 useOptimistic 钩子将在 updateName 请求进行时立即呈现 optimisticName。当更新完成或出错时,React 将自动切换回 currentName 值。
更多信息,请参阅 useOptimistic 的文档。
新的 API:use
在 React 19 中,我们引入了一个新的 API 来读取渲染中的资源:use。
例如,你可以使用use读取promise,React 将挂起,直到promise解析:
import {use} from 'react';
function Comments({commentsPromise}) {
// `use` will suspend until the promise resolves.
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment}</p>);
}
function Page({commentsPromise}) {
// When `use` suspends in Comments,
// this Suspense boundary will be shown.
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
)
}
use 不支持渲染中创建的 Promise
如果你尝试将 render 中创建的 Promise 传递给
use,React会发出警告:
另外,我们还添加了两个新的根选项,以补充
onRecoverableError:
onCaughtError:在 React 在错误边界中捕获错误时调用。onUncaughtError:当错误被抛出且未被错误边界捕获时调用。onRecoverableError:当错误被抛出并自动恢复时调用。有关更多信息和示例,请参阅 createRoot 和 hydrateRoot 的文档。
支持自定义元素
React 19 增加了对自定义元素的全面支持,并通过了在 Custom Elements Everywhere 上的所有测试。
在过去的版本中,在 React 中使用自定义元素一直很困难,因为 React 将无法识别的
props视为attributes而不是properties。在 React 19 中,我们添加了对properties的支持,该支持在客户端和 SSR 期间使用以下策略工作:
- 服务器端渲染:传递给自定义元素的
props如果其类型是像string、number或值为true的原始值,将呈现为attributes。具有非原始类型(如object、symbol、function或值为false)的props将被省略。- 客户端渲染:与自定义元素实例上的
props匹配的属性将被分配为properties,否则它们将被分配为attributes。感谢 Joey Arhar 推动了 React 中自定义元素支持的设计和实现。
如何升级
请参阅 React 19 升级指南,了解逐步说明和突破性以及显著变更的完整列表。
