Nextjs 14 个使用 Shadcn 表单的服务器端操作

问题描述 投票:0回答:1

我想在我的 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}
,我无法让客户端验证工作,并且让服务器端非常困难。我怎样才能在验证是客户端但表单操作是服务器端的情况下得到这个?

  1. 如果我使用 Shadcn 文档中给出的客户端 onSubmit 函数,然后从那里调用服务器操作,它仍然被视为服务器调用还是与调用端点相同?

我尝试在 actions.ts 文件中添加验证,然后返回该验证,但显示它很痛苦。

next.js react-hook-form zod next.js14 shadcnui
1个回答
0
投票

带有 zod 验证的 Nextjs 服务器操作

"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 错误和自定义错误消息

© www.soinside.com 2019 - 2024. All rights reserved.