概述
Server Actions 是在服务器上执行的异步函数,可从 Client Component 和 Server Component 中调用,用于数据变更(mutations)、表单提交以及其他服务端操作。本技能在用户提出 Server Actions、Next.js 表单处理、mutations、useFormState、useFormStatus 等相关问题时使用。
定义 Server Actions
在 Server Component 中,可在异步函数内部使用 'use server' 指令,例如在 app/page.tsx 中定义 createPost(formData),然后将其作为 form 的 action 传入。
在单独文件中,可用 'use server' 标记整个文件,例如 app/actions.ts 中导出 createPost(formData: FormData) 与 deletePost(id: string) 等异步函数。
表单处理
基础表单:在 'use server' 文件的 submitContact 中通过 formData.get 读取 name、email、message,并写入数据库;页面组件引入该 action 并传给 form 的 action 属性,配合必填输入项。
带校验(Zod):使用 zod 定义 schema(如 email 为邮箱、password 最少 8 位),在 signup 中用 schema.safeParse 解析,失败时返回 { error: parsed.error.flatten() },成功则创建用户并返回 { success: true }。
useFormState Hook
用于处理表单状态与错误。在客户端组件中从 react-dom 引入 useFormState,传入 signup 与 initialState(含 error、success),得到 [state, formAction],将 formAction 传给 form。对应的 Server Action 签名接收 prevState 与 formData,可根据校验结果返回错误信息或成功状态。
useFormStatus Hook
用于显示提交中的加载状态。在客户端组件中从 react-dom 引入 useFormStatus,读取 pending,据此禁用提交按钮并显示「Submitting...」或「Submit」。可在表单中引入该提交按钮组件使用。
重新验证
revalidatePath:在 Server Action 中从 next/cache 引入,可重新验证指定路径(如 '/posts')、动态路由(revalidatePath('/posts/[slug]', 'page'))或某路径下所有路径(revalidatePath('/posts', 'layout'))。
revalidateTag:先以 next: { tags: ['posts'] } 的方式带标签获取数据,再在 Server Action 中调用 revalidateTag('posts') 按缓存标签重新验证。
操作后重定向
在 Server Action 中从 next/navigation 引入 redirect,创建文章后调用 redirect(/posts/${post.slug}) 跳转到新文章。
乐观更新
使用 useOptimistic 在操作完成前立即更新 UI。示例中 TodoList 基于 todos 维护乐观列表,提交时先调用 addOptimisticTodo(title) 立即更新界面,再 await addTodo(formData) 执行服务端操作。
非表单用法
可编程调用 Server Actions,例如在客户端组件中通过按钮的 onClick 调用 deletePost(id)。
错误处理
在 Server Action 中使用 try/catch;示例中对 PrismaClientKnownRequestError 的 P2002 错误返回「标题已存在」,其他情况返回「创建文章失败」。
安全注意事项
资料列出:始终校验输入(不要信任客户端数据)、检查身份认证(确认用户已授权)、使用 CSRF 防护(Server Actions 内置)、清理输出(防止 XSS)。示例中 deletePost 先调用 auth() 获取会话,未登录抛 Unauthorized,再检查 post.authorId 是否等于 session.user.id,不符则抛 Forbidden,最后执行删除。
参考资源
资料列出可进一步查看:references/form-handling.md(高级表单模式)、references/revalidation.md(缓存重新验证策略)、examples/mutation-patterns.md(完整的 mutation 示例)。