React 19 Server Actions 实战:把表单提交与数据变更搬回服务端

test12026-10-2722 次阅读

为什么要把变更搬回服务端

传统的 SPA 写表单,需要单独写一个 API 路由、前端用一个请求库去调、再手动更新缓存。Server Actions 让一个 async 函数直接跑在服务端,组件里像调用本地函数一样调用它,省掉一层样板。

定义一个 Server Action

在文件顶部标记 "use server",导出异步函数。它接收表单数据或普通参数,在服务端直接操作数据库,返回结构化结果。

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

import { revalidatePath } from "next/cache";
import { db } from "@/lib/db";

export async function createTodo(
  prevState: { ok: boolean; msg: string },
  formData: FormData
) {
  const title = String(formData.get("title") ?? "").trim();
  if (!title) return { ok: false, msg: "标题不能为空" };

  await db.todo.create({ data: { title } });
  revalidatePath("/todos");
  return { ok: true, msg: "已创建" };
}

在表单里直接用 useActionState

React 19 的 useActionState 把 action 与状态绑定,pending 态、错误信息都能直接拿到,不用自己管 loading。

// app/todos/new.tsx
"use client";
import { useActionState } from "react";
import { createTodo } from "../actions";

export function NewTodoForm() {
  const [state, formAction, pending] = useActionState(createTodo, {
    ok: true,
    msg: "",
  });
  return (
    <form action={formAction}>
      <input name="title" disabled={pending} />
      <button disabled={pending}>{pending ? "提交中" : "创建"}</button>
      {!state.ok && <p>{state.msg}</p>}
    </form>
  );
}

通用数据变更也能用

不止表单,普通按钮点击也可以通过事件触发 action,变更后自动刷新相关数据。

// 直接在事件里调用
async function onDelete(id: string) {
  await deleteTodo(id);
  revalidatePath("/todos");
}

工程注意点

  • Server Action 默认有 POST 语义,不要把它暴露成 GET 请求,避免被预取时误触发。
  • 参数和返回值都要可序列化,函数、Symbol 这类不能直接传。
  • 涉及权限的变更,必须在 action 内部再校验一次当前用户,不要只靠前端隐藏按钮。
  • 用 revalidatePath / revalidateTag 精准失效缓存,比整页刷新更省。
T

test1

文章作者

为什么要把变更搬回服务端 传统的 SPA 写表单,需要单独写一个 API 路由、前端用一个请求库去调、再手动更新缓存。...

分类
技术
发布时间
2026-10-27
字数
约 1590 字
阅读
22 次