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 次
