React 19 带来了一系列新功能,赋予了开发者更多能力。这篇文章将概述 React 19 的新特性,以及如何使用它们。
React 19 新特性介绍 🚀
异步函数的操作
React 19 引入了 Actions 功能,简化了异步请求的处理。此功能会自动管理待处理状态、错误和乐观更新。借助 useTransition,开发者现在可以更直观地处理异步操作,在数据变更时保持用户界面的响应性。
js
// 使用 Actions 中的待定状态
function UpdateName({}) {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();
const handleSubmit = () => {
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>
);
}
简化表单处理
新的 <form>
Actions 可自动处理表单提交,为了使 Actions 的常见情况更加简单,React 19 添加了一个名为 useActionState
的新 Hook,这是一个可以根据某个表单动作的结果更新 state 的 Hook。
js
// 使用 <form> Actions 和 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 null;
}, null);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>
Update
</button>
{error && <p>{error}</p>}
</form>
);
}
useOptimistic 的乐观更新功能
useOptimistic
Hook 使开发者能够在实际数据变更于后台执行时,即时在用户界面上呈现更新结果。该 hook 通过管理临时 UI 状态实现这一机制,若操作失败则会自动恢复至原始状态。
js
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>
);
}
通过 useFormStatus 访问表单状态
引入 useFormStatus
钩子来直接访问表单提交的状态,这一特性非常适合用于构建需要实时反馈提交状态的组件,无需通过逐层传递属性即可实现状态同步,显著提升了组件设计的便捷性。
js
import {useFormStatus} from 'react-dom';
function DesignButton() {
const {pending} = useFormStatus();
return <button type="submit" disabled={pending} />
}
全新数据读取API:use
在 React 19 中,新增了一个新的 API 用来在渲染中读取资源:use
。 例如,你可以使用 use
读取一个 promise,React 将挂起,直到 promise 解析完成:
js
import { use } from "react";
function Comments({ commentsPromise }) {
// `use` 将被暂停直到 promise 被解决.
const comments = use(commentsPromise);
return comments.map((comment) => <p key={comment.id}>{comment}</p>);
}
function Page({ commentsPromise }) {
// 当"use"在注释中暂停时,
// 将显示此悬念边界。
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
);
}
服务器组件与服务器操作
React 19 引入了服务器组件和服务器操作,增强了 React 应用程序的功能。这些功能允许开发者通过将某些任务转移到服务器来优化性能和资源利用率。
React 19 中的改进
ref
作为一个属性
从 React 19 开始,你现在可以在函数组件中将 ref
作为 prop 进行访问,新的函数组件将不再需要 forwardRef
:
js
function MyInput({placeholder, ref}) {
return <input placeholder={placeholder} ref={ref} />
}
//...
<MyInput ref={ref} />
<Context>
作为提供者
在 React 19 中,你可以直接使用 <Context>
代替 <Context.Provider>
:
js
const ThemeContext = createContext('');
function App({children}) {
return (
<ThemeContext value="dark">
{children}
</ThemeContext>
);
}
refs 支持清理函数
这将使得在 ref
改变时执行清理操作变得更加容易。例如,你可以在 ref
改变时取消订阅事件:
js
<input
ref={(ref) => {
// ref 创建
// 新特性: 当元素从 DOM 中被移除时
// 返回一个清理函数来重置 ref
return () => {
// ref cleanup
};
}}
/>
当组件卸载时,React 将调用从 ref
回调返回的清理函数。
useDeferredValue
初始化 value
React 19 为 useDeferredValue
新增了 initialValue
参数:
javascript
function Search({ deferredValue }) {
// 首次渲染时值为 ''
// 随后会调度用 deferredValue 重新渲染
const value = useDeferredValue(deferredValue, "");
return <Results query={value} />;
}
当提供了 initialValue, useDeferredValue
将在组件的初始渲染中返回它作为 value
, 并在后台安排一个使用返回的 deferredValue 重新渲染。
支持文档元数据
文档元数据支持 React 19 原生支持在组件内直接渲染文档元数据标签(<title>
、<link>
和 <meta>
),无需依赖 react-helmet 等第三方库即可更轻松地管理元数据,确保在客户端渲染、服务端渲染及流式渲染等场景下的兼容性。服务端渲染时需在组件树渲染完成前确保元数据可访问。
js
function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<title>{post.title}</title>
<meta name="author" content="Josh" />
<link rel="author" href="https://twitter.com/joshcstory/" />
<meta name="keywords" content={post.keywords} />
<p>Eee equals em-see-squared...</p>
</article>
);
}
支持样式表
内置支持外部样式表和内联样式表管理,允许组件指定样式表优先级。React 将根据优先级自动优化样式表在 DOM 中的插入顺序,简化了并发渲染和服务器的流式渲染中的样式处理。
支持异步脚本
支持在组件树任意位置渲染异步脚本,React 会对多个组件渲染的相同脚本进行去重处理,确保异步脚本只加载一次。
js
function MyComponent() {
return (
<div>
<script async={true} src="..." />
Hello World
</div>
);
}
支持预加载资源
在初始文档加载和客户端更新时,尽早告诉浏览器它可能需要加载的资源,可以显著提高页面性能。
React 19 包含了一些新的 API,用于加载和预加载浏览器资源,使得构建不受资源加载效率影响的优秀体验变得尽可能容易。
js
import { prefetchDNS, preconnect, preload, preinit } from "react-dom";
function MyComponent() {
preinit("https://.../path/to/some/script.js", { as: "script" }); // 立即加载并执行此脚本
preload("https://.../path/to/font.woff", { as: "font" }); // 预加载此字体
preload("https://.../path/to/stylesheet.css", { as: "style" }); // 预加载此样式表
prefetchDNS("https://..."); // 当你实际上没有向该主机请求任何东西时
preconnect("https://..."); // 当你想请求某件事但又不确定是什么的时候
}
兼容第三方脚本和扩展
React 19 改进了激活机制,以考虑第三方脚本和浏览器扩展。
在激活过程中,如果在客户端渲染的元素与从服务器获取的 HTML 中找到的元素不匹配,React 将强制进行客户端重新渲染以修复内容。以前,如果一个元素是由第三方脚本或浏览器扩展插入的,它会触发一个不匹配的错误并进行客户端渲染。
在 React 19 中,<head>
和 <body>
中的意外标签将被跳过,避免了不匹配的错误。如果 React 需要由于无关的激活不匹配而重新渲染整个文档,它将保留由第三方脚本和浏览器扩展插入的样式表。
总结
React 19 引入了强大的新功能,例如简化的状态管理、改进的错误处理和简化的异步操作。借助服务器组件和服务器操作,它优化了性能和资源利用率。增强了与第三方脚本和扩展的兼容性,使 React 变得更加好用。