React 19 已于 2024 年 12 月 5 日正式发布,并在 npm 上稳定可用。这一版本带来了诸多令人振奋的新特性和改进,旨在简化开发流程、提升性能,并增强与现代开发需求的兼容性。本文将详细介绍 React 19 的主要新特性、改进、状态管理的变化以及如何顺利升级,帮助开发者充分利用这些新功能构建高效、响应迅速的应用。
目录
主要新特性
Actions
概述
在 React 应用中,常见的操作是执行数据变更并随后更新状态。例如,当用户提交表单更改姓名时,你需要发起 API 请求,并处理响应。在之前的版本中,开发者需要手动处理待处理状态、错误、乐观更新和顺序请求等。然而,React 19 引入了 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>
);
}
升级后:使用 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>
);
}
优势
- 待处理状态:Actions 自动管理请求的开始和结束状态,减少手动设置状态的繁琐。
- 乐观更新:通过
useOptimistic
钩子,用户可以在请求进行时立即看到更新结果,提高响应性。 - 错误处理:自动处理错误,支持显示错误边界并回滚乐观更新。
- 表单支持:
<form>
元素支持传递函数到action
和formAction
属性,自动提交和重置表单。
新钩子(Hooks)
React 19 引入了多个新钩子,进一步简化状态管理和数据处理。
useActionState
功能:简化 Actions 的使用,返回错误、提交动作和待处理状态。
示例
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
return error;
}
redirect("/path");
return null;
},
null,
);
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>
);
}
use
功能:在渲染时读取资源(如 Promise),并支持 Suspense。
示例
import { use } from 'react';
function Comments({ commentsPromise }) {
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment}</p>);
}
function Page({ commentsPromise }) {
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
);
}
注意:use
不能用于在渲染过程中创建的 Promise,需确保 Promise 来自 Suspense 兼容的库或框架。
React DOM Static APIs
prerender 和 prerenderToNodeStream
功能:改进静态 HTML 生成,支持数据加载等待,适用于流式渲染环境。
示例
import { prerender } from 'react-dom/static';
async function handler(request) {
const { prelude } = await prerender(<App />, {
bootstrapScripts: ['/main.js']
});
return new Response(prelude, {
headers: { 'content-type': 'text/html' },
});
}
React Server Components
Server Components
功能:允许在独立于客户端应用或 SSR 服务器的环境中预渲染组件,适用于全栈 React 架构。
特点
- 运行环境独立于客户端或 SSR 服务器。
- 可在构建时或每个请求时执行。
Server Actions
功能:允许客户端组件调用在服务器上执行的异步函数,通过 "use server"
指令实现。
示例
// Server Component
'use server';
export async function fetchData() {
// 服务器端逻辑
}
// Client Component
import { fetchData } from './ServerComponent';
function ClientComponent() {
const handleClick = async () => {
const data = await fetchData();
// 处理数据
};
return <button onClick={handleClick}>Fetch Data</button>;
}
改进与优化
ref 作为属性
功能:函数组件现在可以直接接收 ref
作为属性,无需使用 forwardRef
。
示例
function MyInput({ placeholder, ref }) {
return <input placeholder={placeholder} ref={ref} />;
}
// 使用方式
<MyInput ref={inputRef} />