React 19 新特性实战体验
React 19 发布有一段时间了,新项目试着用了一下,记录些感受。
新特性一览
| 特性 | 说明 | 稳定性 |
|---|---|---|
| use() Hook | 读取 Promise 和 Context | 稳定 |
| Server Components | 服务端组件 | 稳定 |
| Actions | 表单处理新模式 | 稳定 |
| useOptimistic | 乐观更新 | 稳定 |
| useActionState | 表单状态管理 | 稳定 |
use() Hook
以前读 Promise 要用 useEffect + useState,现在可以直接用:
function UserProfile({ id }) {
const user = use(fetchUser(id));
return <div>{user.name}</div>;
}
简洁多了。但有个坑:如果 Promise reject,会触发最近的 ErrorBoundary。
<ErrorBoundary fallback={<div>加载失败</div>}>
<UserProfile id={123} />
</ErrorBoundary>
Actions
表单处理终于不用自己写了:
function ContactForm() {
const [state, submitAction] = useActionState(async (prevState, formData) => {
const result = await submitContact(formData);
return { success: result.ok, message: result.message };
}, { success: false, message: '' });
return (
<form action={submitAction}>
<input name="email" type="email" required />
<textarea name="message" required />
<button type="submit">提交</button>
{state.message && <p>{state.message}</p>}
</form>
);
}
配合 Server Actions 更香:
// server-action.js
'use server';
export async function submitContact(formData) {
const email = formData.get('email');
const message = formData.get('message');
// 直接操作数据库
await db.contacts.create({ email, message });
return { ok: true, message: '提交成功' };
}
useOptimistic 乐观更新
点赞、收藏这种操作,用户期望立即响应:
function LikeButton({ postId, initialLiked }) {
const [liked, setLiked] = useState(initialLiked);
const [optimisticLiked, addOptimistic] = useOptimistic(liked);
async function handleLike() {
addOptimistic(true);
await toggleLike(postId);
setLiked(true);
}
return (
<button onClick={handleLike} disabled={optimisticLiked}>
{optimisticLiked ? '已点赞' : '点赞'}
</button>
);
}
用户点下去立刻看到效果,不用等网络请求。
迁移踩坑
1. forwardRef 不再必需
// 以前
const MyInput = forwardRef((props, ref) => <input ref={ref} {...props} />);
// 现在
function MyInput(props) {
return <input {...props} />;
}
// 直接传 ref 即可
<MyInput ref={inputRef} />
但老项目里用了 forwardRef 的不用改,兼容的。
2. useEffect 变化
严格模式下,useEffect 会执行两次清理函数,确保副作用可重复执行。之前没写好清理函数的会暴露问题。
3. Suspense 支持
use() 配合 Suspense,自动处理加载状态:
<Suspense fallback={<Spinner />}>
<UserProfile id={123} />
</Suspense>
比手动管理 loading 状态舒服多了。
性能对比
重构了一个中等规模的项目:
| 指标 | React 18 | React 19 | 变化 |
|---|---|---|---|
| 首屏时间 | 1.8s | 1.5s | -17% |
| 包体积 | 145KB | 138KB | -5% |
| 代码行数 | 4200 | 3800 | -10% |
代码量减少主要是因为 Actions 替代了手写的表单处理逻辑。
总结
React 19 值得升级,尤其是新项目。Actions 和 use() 确实能减少样板代码。
老项目升级前建议看看迁移指南,有些边界情况需要处理。我们花了两天时间完成迁移,主要是测试工作量。