Effortless Form Handling: Mastering the Art with React Hook Forms
Form handling is a crucial aspect of web development, and when it comes to building forms in a Next.js/React applications, using powerful tools like React Hook Form and Zod can greatly enhance your development experience. In this article, we’ll dive into the integration of React Hook Form with Zod to create a seamless and efficient form handling process in a React JS application.
Getting Started
Let’s start by understanding the key components of our form handling setup. The following code provides a basic template for a React application with a form that utilizes React Hook Form and Zod for validation.
import { zodResolver } from "@hookform/resolvers/zod";
import { SubmitHandler, useForm } from "react-hook-form";
import { z } from "zod";
const schema = z.object({
email: z.string().email(),
message: z.string().min(8),
});
type FormFields = z.infer<typeof schema>;
export default function App() {
const {
register,
handleSubmit,
setError,
formState: { errors, isSubmitting },
} = useForm<FormFields>({
defaultValues: {
email: "test@email.com",
},
resolver: zodResolver(schema),
});
const onSubmit: SubmitHandler<FormFields> = async (data) => {
try {
// Simulating an asynchronous operation (e.g., API request)
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log(data);
} catch (error) {
// Setting an error for the 'email' field
setError("email", {
message: "This email is already taken",
});
}
};
return (
<div className="App">
<h1>React Hook Form with Zod</h1>
<form onSubmit={handleSubmit(onSubmit)}>
{/* Email input field */}
<input {...register("email")} type="text" placeholder="Email" />
{errors.email && <div>{errors.email.message}</div>}
{/* Message textarea */}
<textarea
{...register("message")}
name="message"
cols="30"
rows="10"
placeholder="Type your message here"
></textarea>
{errors.message && <div>{errors.message.message}</div>}
{/* Submit button */}
<button disabled={isSubmitting} type="submit">
{isSubmitting ? "Loading..." : "Submit"}
</button>
{/* Root-level error message */}
{errors.root && <div>{errors.root.message}</div>}
</form>
</div>
);
}
Breakdown of the Code
1. Schema Definition
We start by defining a Zod schema to validate our form fields. In this example, the schema includes an email
field with email validation and a message
field with a minimum length of 8 characters.
const schema = z.object({
email: z.string().email(),
message: z.string().min(8),
});
2. useForm Hook
The useForm
hook from React Hook Form is employed to manage the form state and handle form submission. We pass our Zod schema to the resolver
option to enable automatic validation.
const {
register,
handleSubmit,
setError,
formState: { errors, isSubmitting },
} = useForm<FormFields>({
defaultValues: {
email: "test@email.com",
},
resolver: zodResolver(schema),
});
3. Form Submission
The onSubmit
function handles the form submission. It includes an asynchronous operation (simulated API request) and showcases how to set a specific error for the email
field using setError
.
const onSubmit: SubmitHandler<FormFields> = async (data) => {
try {
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log(data);
} catch (error) {
setError("email", {
message: "This email is already taken",
});
}
};
4. Form Rendering
The actual form rendering includes input fields for email
and message
, along with error messages for each field. The submit button is disabled during the submission process, and a root-level error message is displayed if applicable.
<form onSubmit={handleSubmit(onSubmit)}>
{/* Email input field */}
<input {...register("email")} type="text" placeholder="Email" />
{errors.email && <div>{errors.email.message}</div>}
{/* Message textarea */}
<textarea
{...register("message")}
name="message"
cols="30"
rows="10"
placeholder="Type your message here"
></textarea>
{errors.message && <div>{errors.message.message}</div>}
{/* Submit button */}
<button disabled={isSubmitting} type="submit">
{isSubmitting ? "Loading..." : "Submit"}
</button>
{/* Root-level error message */}
{errors.root && <div>{errors.root.message}</div>}
</form>
Conclusion
In this article, we’ve explored the integration of React Hook Form and Zod for seamless form handling in a ReactJS application. Leveraging the capabilities of these libraries can significantly simplify the process of creating robust and efficient forms, offering a smooth user experience. Feel free to customize and extend this example to suit the specific requirements of your projects. Happy coding!