React Server Actions 入门与进阶:从表单提交到数据突变的最佳实践

By | 2026年7月3日

前言

React Server Actions 是 React 19 引入的一项革命性特性,允许直接在服务器端执行函数,无缝处理数据突变(mutations)。它简化了传统的前后端交互模式,尤其适合表单提交、数据更新等场景。本文将带你从零开始,掌握 Server Actions 的核心用法、最佳实践以及常见陷阱,让你在实际项目中游刃有余。

环境准备

确保你的项目使用 React 19 及以上版本,并搭配 Next.js 14+(App Router)或支持 Server Actions 的框架。本文示例基于 Next.js 14。


npx create-next-app@latest my-app --typescript
cd my-app

基础入门:第一个 Server Action

1. 定义 Action

在 Next.js 中,Server Actions 可以定义在文件顶部(使用 "use server" 指令)或单独的文件中。最简单的形式:


// app/actions.ts
"use server";

export async function createUser(formData: FormData) {
  const name = formData.get("name") as string;
  const email = formData.get("email") as string;

  // 模拟数据库操作
  console.log("Creating user:", { name, email });
  return { success: true };
}

2. 在客户端组件中使用


// app/page.tsx
"use client";

import { createUser } from "./actions";

export default function Home() {
  return (
    <form action={createUser}>
      <input name="name" placeholder="Name" required />
      <input name="email" type="email" placeholder="Email" required />
      <button type="submit">Submit</button>
    </form>
  );
}

> 💡 注意action 属性直接接收 Server Action 函数,无需手动调用 fetchaxios。表单提交会自动发送请求并处理响应。

进阶用法:数据验证与错误处理

1. 使用 Zod 进行验证


"use server";

import { z } from "zod";

const schema = z.object({
  name: z.string().min(2, "Name must be at least 2 characters"),
  email: z.string().email("Invalid email"),
});

export async function createUser(formData: FormData) {
  const validated = schema.safeParse({
    name: formData.get("name"),
    email: formData.get("email"),
  });

  if (!validated.success) {
    return { errors: validated.error.flatten().fieldErrors };
  }

  // 处理有效数据
  console.log("Validated data:", validated.data);
  return { success: true };
}

2. 客户端展示错误


"use client";

import { createUser } from "./actions";
import { useActionState } from "react";

export default function Home() {
  const [state, formAction] = useActionState(createUser, { errors: {} });

  return (
    <form action={formAction}>
      <input name="name" placeholder="Name" />
      {state.errors?.name && <p style={{ color: "red" }}>{state.errors.name}</p>}
      <input name="email" type="email" placeholder="Email" />
      {state.errors?.email && <p style={{ color: "red" }}>{state.errors.email}</p>}
      <button type="submit">Submit</button>
    </form>
  );
}

> 💡 提示useActionState(React 19 新增)可以管理 Action 的状态,包括错误和加载状态。

客户端组件与 Server Actions 的交互

1. 调用 Server Action 并刷新数据


"use client";

import { revalidatePath } from "next/cache";
import { deleteUser } from "./actions";

export function DeleteButton({ userId }: { userId: string }) {
  const handleDelete = async () => {
    await deleteUser(userId);
    // 注意:不能直接在客户端组件中调用 revalidatePath,需要从 Action 内部触发
  };

  return <button onClick={handleDelete}>Delete</button>;
}

正确做法:在 Server Action 中调用 revalidatePath


"use server";

import { revalidatePath } from "next/cache";

export async function deleteUser(userId: string) {
  // 删除用户逻辑
  revalidatePath("/users"); // 重新获取用户列表
  return { success: true };
}

2. 传递非表单数据

如果 Action 需要接收非表单数据(如 JSON 对象),可以通过 bind 或直接调用:


"use client";

import { updateUser } from "./actions";

export function UpdateButton({ user }: { user: { id: string; name: string } }) {
  const handleUpdate = async () => {
    await updateUser(user);
  };

  return <button onClick={handleUpdate}>Update</button>;
}

"use server";

export async function updateUser(user: { id: string; name: string }) {
  // 更新逻辑
}

常见陷阱与最佳实践

1. 避免在客户端组件中直接修改状态

Server Actions 是异步的,不要在 onClick 中直接调用并期望立即更新状态。使用 useActionStatestartTransition 来管理。

2. 安全性:永远不要信任客户端数据

始终在 Server Action 中进行验证和授权检查。


"use server";

export async function deleteUser(userId: string) {
  const session = await getSession();
  if (!session || session.user.id !== userId) {
    throw new Error("Unauthorized");
  }
  // 删除逻辑
}

3. 使用 useActionState 处理加载状态


const [state, formAction, isPending] = useActionState(createUser, { errors: {} });

return (
  <form action={formAction}>
    <button disabled={isPending}>{isPending ? "Submitting..." : "Submit"}</button>
  </form>
);

4. 错误边界

对于未捕获的错误,可以使用 React 错误边界或 Next.js 的 error.js 文件。

总结

React Server Actions 极大简化了数据突变流程,让前端开发者无需手动管理 API 路由。通过本文的学习,你应该掌握了:

  • 定义和使用 Server Actions
  • 结合 Zod 进行数据验证
  • 在客户端组件中处理状态和错误
  • 调用 Server Actions 并触发缓存刷新
  • 安全性和性能最佳实践

下一步,可以探索 Server Actions 与 Streaming、Suspense 的结合,以及如何在大型项目中组织 Action 代码。

延伸阅读