Next.js Discord

Discord Forum

How to use react-hook-form with form action

Unanswered
Sun bear posted this in #help-forum
Open in Discord
Sun bearOP
This code doesn't trigger any validation on submit
const FormSchema = z.object({
  email: z
    .string()
    .min(1, { message: "." })
  password: z
    .string()
    .min(4, { message: "." }),
});

const form = useForm<z.infer<typeof FormSchema>>({
    resolver: zodResolver(FormSchema),
    defaultValues: {
      email: "",
      password: "",
    },
  });

 const handleLogin = async (formData: FormData) => {
    const email = formData.get("email") as string;
    const password = formData.get("password") as string;
    let user = await signIn(email, password);
    if (isUser(user)) {
      const { email, isSignedIn, error } = user;
      if (!error.isError) {
        setSession(user);
        redirect("/dashboard");
      }
    }
  };

<Form {...form}>
      <form
        action={(formData) => startTransition(() => handleLogin(formData))}
        className="w-2/3 space-y-6"
      >
        <h1 className="text-4xl text-center font-semibold">Login</h1>
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input type="email" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name="password"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Password</FormLabel>
              <FormControl>
                <Input type="password" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button
          type="submit"
          className="w-full"
          disabled={isPending}
        >
          Login
          {isPending ? (
            <ReloadIcon className="mx-2 h-4 w-4 animate-spin" />
          ) : null}
        </Button>
      </form>
    </Form>

12 Replies

Sun bearOP
Sun bearOP
Any ideas where the error might be?
Barbary Lion
have you tried it without startTransition ?
action={handleLogin}
Sun bearOP
Nope, it didn't validate. It needs form.handleSubmit But i am unable to figure out how to do it with actions?
Also I am new to nextjs. Is it even worth using action={}? can't I just call the server action inside a handleSubmit? why is everyone using action?
Barbary Lion
yeah so ive seen nothing but issues and confusion with server actions and wouldnt recommend them. I'd use more common stable patterns that have been around for a while. Heres an example with react-hook-form

          <Form {...form}>
            <form
              onSubmit={form.handleSubmit(handleSubmit)}
              className="space-y-4"
            >
              <FormField
                disabled={isLoading}
                control={form.control}
                name="agencyLogo"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Agency Logo</FormLabel>
                    <FormControl>
                      <FileUpload
                        apiEndpoint="agencyLogo"
                        onChange={field.onChange}
                        value={field.value}
                      />
                    </FormControl>
                    <FormMessage />
                  </FormItem>
                )}
              />
  const handleSubmit = async (values: z.infer<typeof FormSchema>) => {
    try {
      let newUserData
      let custId
      if (!data?.id) {
        const bodyData = {
          email: values.companyEmail,
          name: values.name,
          shipping: {
            address: {
              city: values.city,
              country: values.country,
              line1: values.address,
              postal_code: values.zipCode,
              state: values.zipCode,
            },
            name: values.name,
          },
          address: {
            city: values.city,
            country: values.country,
            line1: values.address,
            postal_code: values.zipCode,
            state: values.zipCode,
          },
        }

        const customerResponse = await fetch('/api/stripe/create-customer', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(bodyData),
        })
        const customerData: { customerId: string } =
          await customerResponse.json()
        custId = customerData.customerId
      }
  const form = useForm<z.infer<typeof FormSchema>>({
    mode: 'onChange',
    resolver: zodResolver(FormSchema),
    defaultValues: {
      name: data?.name,
      companyEmail: data?.companyEmail,
      companyPhone: data?.companyPhone,
      whiteLabel: data?.whiteLabel || false,
      address: data?.address,
      city: data?.city,
      zipCode: data?.zipCode,
      state: data?.state,
      country: data?.country,
      agencyLogo: data?.agencyLogo,
    },
  })
Sun bearOP
Thanks!
Barbary Lion
No problem!