I am trying to build a registration form with Next.js, react-hook-form, and Zod. I have the following code for the form component:
'use client';
import { z } from "zod";
import { useRef } from "react";
import { useForm } from "react-hook-form";
import { useFormState, useFormStatus } from "react-dom";
import { zodResolver } from "@hookform/resolvers/zod";
import { registerSchema } from "@/lib/schemas";
import { RegisterProps } from "@/lib/definitions";
function RegisterForm({ onRegister }: RegisterProps) {
const formRef = useRef<HTMLFormElement>(null);
const form = useForm<z.infer<typeof registerSchema>>({
resolver: zodResolver(registerSchema),
defaultValues: {
fullName: "",
email: "",
password: "",
},
});
const [state, registerAction] = useFormState(onRegister, { message: "" });
return (
<Form {...form}>
<form
ref={formRef}
action={registerAction}
className="space-y-4"
onSubmit={form.handleSubmit(() => formRef?.current?.submit())}
>
...
</form>
</Form>
);
}
My validation works fine, but my action (registerAction
) never runs. I get the following error when I hit submit on the form:
Error: A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you're trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().
I have tried using the requestSubmit()
method. The form does not submit, but I don't get the error anymore. I am trying to understand why this happens. Calling the action as in the code snippet below, my action is invoked and the user is registered. Why does the method below work?
const onSubmit = (data: z.infer<typeof registerSchema>) => {
const formData = new FormData()
formData.set('fullName', data.fullName;
formData.set('email', data.email;
formData.set('password', data.password;
registerAction(formData)
}
return (
<Form {...form}>
<form
ref={formRef}
className="space-y-4"
onSubmit={form.handleSubmit(onSubmit)}
>
...
</form>
</Form>
);
handleSubmit
will preventDefault and receive the form data if form validation is successful. before invoking "onSubmit"
react-hook-form
give you all this By default
so you don't need ref
you can just pass your server action in handleSubmit
<Form {...form}>
<form
className="space-y-4"
onSubmit={form.handleSubmit((values)=> registerAction(values) )}
>
...
</form>
</Form>
and You can pass an async function and await res from server
const onSubmit = async (data) => {
try {
const res = await registerAction(values)
consloe.log(res)
} catch (e) {
// handle your error
}
};
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit(data)} >
...
</form>
</Form>