返回首页
🎨 前端 / Web

React 19 稳定版特性:Actions、useOptimistic、Server Functions

React 19 引入 Actions / useOptimistic / Server Functions。本文从源码角度解读新特性,及从 18 迁移的注意事项。

React · React 19 · Actions · useOptimistic · Server Functions
📰

今日技术简讯

📰 技术简讯 · 2026-05-06

今日聚合 6 条热门技术内容。

🤖 AI / LLM

1. OpenAI 推出 Skills 协议

🎨 前端 / Web

2. React 19 稳定版特性

  • 链接https://react.dev/blog/react-19
  • 来源:React 官方
  • 摘要:React 19 稳定版发布,Actions / useOptimistic / Server Functions 全栈支持。

3. Vite 6 推出 Rolldown 引擎

⚙️ 后端 / 架构

4. PostgreSQL 17.2 发布

🚀 独立开发 / OPC

5. Dub.co 推出 Conversions API

6. ConvertKit 推出 Newsletter AI


数据来源:掘金 / InfoQ 中文 / HN / GitHub / Dev.to 采集时间:2026-05-06 09:00 (UTC+8)

📝

今日深度文

React 19 稳定版特性:Actions、useOptimistic、Server Functions

一句话结论:React 19 把"全栈"作为一等公民。Actions 让表单处理不再需要 useState + onSubmit + try/catch 模板。

背景

React 19 在 2026 年 Q1 进入稳定版,引入 3 个核心特性:

  • Actions:声明式数据变更
  • useOptimistic:乐观更新 UI
  • Server Functions:服务端代码在客户端透明调用

4 个核心新特性

1. Actions:声明式数据变更

// React 18:手动处理 loading + error + form state
function AddTodo() {
  const [text, setText] = useState("");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  async function handleSubmit(e) {
    e.preventDefault();
    setLoading(true);
    try {
      await fetch("/api/todos", {
        method: "POST",
        body: JSON.stringify({ text }),
      });
      setText("");
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      {error && <p>{error}</p>}
      <button disabled={loading}>
        {loading ? "保存中..." : "添加"}
      </button>
    </form>
  );
}

// React 19:用 Action 一行搞定
function AddTodo() {
  async function action(formData: FormData) {
    "use server";
    await db.todos.insert({
      text: formData.get("text"),
    });
  }

  return (
    <form action={action}>
      <input name="text" />
      <button>添加</button>
    </form>
  );
}

代码量减少 80%

2. useOptimistic:乐观更新

import { useOptimistic } from "react";

function CommentList({ comments }: { comments: Comment[] }) {
  const [optimisticComments, addOptimistic] = useOptimistic(
    comments,
    (state, newComment: Comment) => [...state, newComment]
  );

  async function add(formData: FormData) {
    "use server";
    const comment = await db.comments.insert({
      text: formData.get("text"),
    });
    // 立即在 UI 显示(不等服务器返回)
    addOptimistic(comment);
  }

  return (
    <div>
      {optimisticComments.map((c) => (
        <Comment key={c.id} comment={c} />
      ))}
      <form action={add}>
        <input name="text" />
        <button>提交</button>
      </form>
    </div>
  );
}

用户体验:UI 立即响应,无需等待服务器。

3. Server Functions:服务端透明调用

// 服务端函数(在 'use server' 文件中)
// app/actions.ts
"use server";

export async function getUser(id: string) {
  const user = await db.users.findUnique({ where: { id } });
  return user;
}

// 客户端调用(自动 RPC)
"use client";
import { getUser } from "@/app/actions";

function UserProfile({ id }: { id: string }) {
  const user = use(getUser(id));  // Suspense 集成
  return <div>{user.name}</div>;
}

优势

  • 不用写 API endpoint
  • 不用 fetch
  • 类型安全(自动 RPC)

4. 新 Hooks

// useFormStatus:获取表单提交状态
import { useFormStatus } from "react-dom";

function SubmitButton() {
  const { pending } = useFormStatus();
  return <button disabled={pending}>{pending ? "提交中..." : "提交"}</button>;
}

// useActionState:管理 action 状态
import { useActionState } from "react";

function Form() {
  const [state, action, isPending] = useActionState(serverAction, initialState);
  return (
    <form action={action}>
      <input name="email" />
      {state.error && <p>{state.error}</p>}
      <button disabled={isPending}>提交</button>
    </form>
  );
}

// use():读取 Promise / Context
import { use } from "react";

function Profile({ userPromise }: { userPromise: Promise<User> }) {
  const user = use(userPromise);  // 自动 Suspense
  return <div>{user.name}</div>;
}

5 个真实应用场景

场景 1:电商购物车

// 之前:客户端状态 + fetch + 缓存
// 现在:Server Function + useOptimistic
"use server";
export async function addToCart(itemId: string) {
  await db.cart.insert({ itemId, userId: getCurrentUser().id });
  revalidateTag("cart");
}

// 客户端
function AddToCartButton({ itemId }: { itemId: string }) {
  const [, startTransition] = useTransition();
  return (
    <button onClick={() => startTransition(() => addToCart(itemId))}>
      加入购物车
    </button>
  );
}

场景 2:实时评论

// useOptimistic 让评论立即显示
const [optimistic, addOptimistic] = useOptimistic(comments, ...);

场景 3:表单提交

// useActionState 自动管理表单状态
const [state, action, pending] = useActionState(submitForm, { error: null });

场景 4:SSR 数据获取

// use() 简化 Suspense 集成
const user = use(userPromise);

场景 5:表单验证

// Action 返回错误信息,自动展示
async function action(prev, formData) {
  const result = await validateAndSave(formData);
  if (!result.success) {
    return { error: result.error };  // 自动返回给前端
  }
  redirect("/success");
}

从 React 18 迁移

Step 1:升级依赖

npm install react@19 react-dom@19
npm install @types/react@19 @types/react-dom@19

Step 2:更新 useTransition

// React 18
const [pending, startTransition] = useTransition();

// React 19:pending 已废弃(用 useFormStatus 替代)
const [, startTransition] = useTransition();

Step 3:Action 改造

// ❌ React 18
const onSubmit = async (e) => { ... };

// ✅ React 19
async function action(formData) { ... }
<form action={action}>

Step 4:处理 StrictMode 警告

// React 19 的 StrictMode 会运行两次 effect
// 确保 effect 是幂等的
useEffect(() => {
  fetchData();
}, []);

5 个常见坑

坑 1:Action 不是函数式组件

// ❌ 错误:把 Action 当事件处理器
<button onClick={action}>提交</button>

// ✅ 正确:用在 form action
<form action={action}>
  <button type="submit">提交</button>
</form>

坑 2:Server Function 不能传非序列化数据

// ❌ 不能传函数 / Date
await serverAction(() => {}, new Date());

// ✅ 只能传可序列化数据
await serverAction("string", 123, { id: 1 });

坑 3:useOptimistic 必须配 useTransition

// ❌ 单独使用 useOptimistic 没有效果
const [optimistic, addOptimistic] = useOptimistic(...);

// ✅ 必须配 startTransition
const [isPending, startTransition] = useTransition();
startTransition(() => addOptimistic(newComment));

坑 4:Action 的错误必须手动捕获

async function action(formData) {
  "use server";
  try {
    await db.insert(formData);
  } catch (err) {
    return { error: err.message };  // 返回错误
  }
}

坑 5:Suspense 边界必须包裹 use()

<Suspense fallback={<Loading />}>
  <Profile userPromise={...} />
</Suspense>

我的看法

React 19 是 React 历史上最重要的版本之一

  1. Actions 简化表单处理 80% 代码
  2. useOptimistic 提升用户体验
  3. Server Functions 模糊前后端边界
  4. 新 Hooks 让状态管理更直观

对独立开发者的意义:

  • 减少样板代码(更快迭代)
  • 更好的 UX(optimistic update)
  • 全栈一体化(少学一套 API)

但不要盲目升级

  • 项目还在用 React 16/17 → 优先升 18
  • React 18 项目稳定运行 → 等生态成熟再升 19
  • 新项目 → 直接 React 19 + Next.js 16

参考


本文基于 React 19.0 稳定版,2026 年 5 月最新文档。

📚 同主题文章

🎨 前端 / Web 分类更多