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>

React 19 文档截图

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 19 应用

性能对比

重构了一个中等规模的项目:

指标React 18React 19变化
首屏时间1.8s1.5s-17%
包体积145KB138KB-5%
代码行数42003800-10%

代码量减少主要是因为 Actions 替代了手写的表单处理逻辑。

总结

React 19 值得升级,尤其是新项目。Actions 和 use() 确实能减少样板代码。

老项目升级前建议看看迁移指南,有些边界情况需要处理。我们花了两天时间完成迁移,主要是测试工作量。