我想在我的 NextJS 14 应用程序中使用 Shadcn 表单,并希望像当前一样进行表单验证,但是当提交表单时,我想执行服务器操作。我可以让验证工作或让服务器操作工作,但两者一起工作,它不起作用,因为服务器操作需要表单数据
动作.ts
"use server";
import { formSchema } from "./schema";
export async function onSubmitStudent(
prevState: { message: string },
formData: FormData,
) {
const parse = formSchema.safeParse({
firstName: formData.get("firstName"),
lastName: formData.get("lastName"),
});
if (!parse.success) {
// console.log(parse.error);
// return { message: parse.error };
const fieldErrors = parse.error.issues.map((issue) => ({
field: issue.path[0],
message: issue.message,
}));
return { errors: fieldErrors };
}
const data = parse.data;
console.log("Data: ", data);
}
这是我稍后发出 POST 请求的地方,但现在我尝试在这里进行表单验证,但 def 不起作用,并且很难返回错误并在 UI 中显示它们
页面.tsx
const initialState = {
message: "",
errors: {},
};
export default function Page() {
const { pending } = useFormStatus();
const initialValues: StudentFormValues = {
firstName: "",
lastName: "",
};
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: initialValues,
});
const [state, formAction] = useFormState(onSubmitStudent, initialState);
useEffect(() => {
console.log(state?.errors);
if (Array.isArray(state?.errors)) {
// Check if state.errors is an array before iterating
state.errors.forEach((error) => {
form.setError(error.field, { message: error.message });
});
}
}, [state?.errors]);
return (
<Form {...form}>
<form action={formAction} className="space-y-8">
<FormField
control={form.control}
name="firstName"
render={({ field }) => (
<FormItem>
<FormLabel>First Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage>{state?.errors[0]?.message}</FormMessage>
</FormItem>
)}
/>
<FormField
control={form.control}
name="lastName"
render={({ field }) => (
<FormItem>
<FormLabel>Last Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage>{state?.errors[1]?.message}</FormMessage>
</FormItem>
)}
/>
<Button type="submit" disabled={pending}>
Submit
</Button>
</form>
</Form>
);
}
因此,由于我在这里有
action={formAction}
,我无法让客户端验证工作,并且让服务器端非常困难。我怎样才能在验证是客户端但表单操作是服务器端的情况下得到这个?
我尝试在 actions.ts 文件中添加验证,然后返回该验证,但显示它很痛苦。
"use server";
import { formSchema } from "./schema";
export async function onSubmitStudent(
prevState: { message: string },
formData: FormData,
) {
const parse = formSchema.safeParse({
firstName: formData.get("firstName"),
lastName: formData.get("lastName"),
});
if (!parse.success) {
return {
errors: parse.error.flatten().fieldErrors,
message: undefined
}
}
const data = parse.data;
console.log("Data: ", data);
发送了这样的错误
parse.error.flatten().fieldErrors
然后在组件中使用
export default function Page() {
const { pending } = useFormStatus();
const initialState = {
errors: {
firstName: undefined,
lastName: undefined
},
message: undefined
};
const initialValues: StudentFormValues = {
firstName: "",
lastName: "",
};
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: initialValues,
});
const [state, formAction] = useFormState(onSubmitStudent, initialState);
useEffect(() => {
console.log(state?.errors);
if (Array.isArray(state?.errors)) {
// Check if state.errors is an array before iterating
state.errors.forEach((error) => {
form.setError(error.field, { message: error.message });
});
}
}, [state?.errors]);
return (
<Form {...form}>
<form action={formAction} className="space-y-8">
<FormField
control={form.control}
name="firstName"
render={({ field }) => (
<FormItem>
<FormLabel>First Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage>{state?.errors?.firstName}</FormMessage>
</FormItem>
)}
/>
<FormField
control={form.control}
name="lastName"
render={({ field }) => (
<FormItem>
<FormLabel>Last Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage>{state?.errors?.lastName}</FormMessage>
</FormItem>
)}
/>
<Button type="submit" disabled={pending}>
Submit
</Button>
</form>
</Form>
);
}
here se
initialState
像这样,它具有错误对象的所有类型安全变量
const initialState = {
errors: {
firstName: undefined,
lastName: undefined
},
message: undefined
};
有时您可能需要显示一些消息错误,例如
user not found
或在这种情况下您需要从服务器操作重新运行
return {
errors: undefined,
message: 'User not found.'
}
这就是为什么你也可以处理 zod 错误和自定义错误消息