关于 safe-action-forms
介绍 next-safe-action 表单集成方式的技能,涵盖原生表单和 React Hook Form 适配器。帮助开发者根据表单状态、验证需求及乐观更新选择相应 Hook。
主要功能
- 01使用 useAction 配合原生表单
- 02用 useStateAction 跟踪表单状态
- 03接入 React Hook Form 适配器
- 04支持表单乐观更新
- 05处理 FormData 与架构要求
适用场景
- 01构建简单的 Action 表单
- 02显示字段级验证错误
- 03创建支持乐观更新的表单
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ next-safe-action/ skills --skill safe-action-forms安装后在 Claude Code 中输入/safe-action-forms确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
file-uploads.mdform-actions.mdreact-hook-form.md详细介绍
next-safe-action 表单集成
选项
| 方案 | 适用场景 |
|---|---|
useAction + 原生表单 | 简单表单、无需复杂的校验 UI、程序化触发 |
useStateAction + <form action={formAction}> | 需要跟踪状态、访问 prevResult 和使用完整回调的表单 |
useHookFormAction(RHF 适配器) | 需要字段级错误、在更改或失焦时进行校验的复杂表单 |
useHookFormOptimisticAction | 需要乐观 UI 更新的 RHF 表单 |
useOptimisticStateAction | 需要立即更新 UI,且必须将重叠写入排队并累积的场景(参见 hooks 技能文档) |
快速开始 — useStateAction 表单
"use client";
import { useStateAction } from "next-safe-action/hooks";
import { submitContact } from "@/app/actions";
export function ContactForm() {
const { formAction, result, isPending, hasSucceeded } = useStateAction(submitContact, {
onSuccess: () => toast.success("Message sent!"),
});
return (
<form action={formAction}>
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
{result.validationErrors?.email && (
<p>{result.validationErrors.email._errors?.[0]}</p>
)}
{result.serverError && <p>{result.serverError}</p>}
{hasSucceeded && <p>Message sent!</p>}
<button type="submit" disabled={isPending}>
{isPending ? "Sending..." : "Send"}
</button>
</form>
);
}
注意:useStateAction 要求服务器操作使用 .stateAction() 而不是 .action() 定义;<form action={formAction}> 会传入原始 FormData,因此输入架构必须能够解析 FormData(例如,使用 zod-form-data 中的 zfd.formData({...}))。有关何时使用 useAction 与 useStateAction 的完整决策表,请参见 hooks 技能文档。
快速开始 — 原生表单
"use client";
import { useAction } from "next-safe-action/hooks";
import { submitContact } from "@/app/actions";
export function ContactForm() {
const { execute, result, isPending } = useAction(submitContact);
return (
<form
onSubmit={(e) => {
e.preventDefault();
const fd = new FormData(e.currentTarget);
execute({
name: fd.get("name") as string,
email: fd.get("email") as string,
message: fd.get("message") as string,
});
}}
>
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
{result.validationErrors && (
<p>{result.validationErrors.email?._errors?.[0]}</p>
)}
{result.serverError && <p>{result.serverError}</p>}
{result.data && <p>Message sent!</p>}
<button type="submit" disabled={isPending}>
{isPending ? "Sending..." : "Send"}
</button>
</form>
);
}
快速开始 — React Hook Form 适配器
"use client";
import { useHookFormAction } from "@next-safe-action/adapter-react-hook-form/hooks";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { submitContact } from "@/app/actions";
const schema = z.object({
name: z.string().min(1, "Name is required"),
email: z.string().email("Invalid email"),
message: z.string().min(10, "Message must be at least 10 characters"),
});
export function ContactForm() {
const { form, handleSubmitWithAction, action } = useHookFormAction(
submitContact,
zodResolver(schema),
{
actionProps: {
onSuccess: () => toast.success("Message sent!"),
},
}
);
return (
<form onSubmit={handleSubmitWithAction}>
<input {...form.register("name")} />
{form.formState.errors.name && <p>{form.formState.errors.name.message}</p>}
<input {...form.register("email")} />
{form.formState.errors.email && <p>{form.formState.errors.email.message}</p>}
<textarea {...form.register("message")} />
{form.formState.errors.message && <p>{form.formState.errors.message.message}</p>}
{action.result.serverError && <p>{action.result.serverError}</p>}
<button type="submit" disabled={action.isPending}>
{action.isPending ? "Sending..." : "Send"}
</button>
</form>
);
}
相关文档
入口点
| 包 | 入口点 | 导出项 |
|---|---|---|
@next-safe-action/adapter-react-hook-form | 默认 | mapToHookFormErrors、类型 |
@next-safe-action/adapter-react-hook-form/hooks | Hooks | useHookFormAction、useHookFormOptimisticAction、useHookFormActionErrorMapper |
评论
支持 Markdown