Less Re-Rendering, Cleaner Code
Forms Library — react-hook-form
For anything beyond a tiny form, `react-hook-form` saves re-renders and reads cleaner than hand-rolled controlled state.
What you'll learn
- Set up a basic form with `react-hook-form`
- Validate inputs
- Recognize when the library is worth it
For tiny forms, controlled useState is fine (chapter 3). For
anything bigger — many fields, async validation, complex shapes —
react-hook-form is what most teams use.
Install
npm install react-hook-form A Basic Form
import { useForm } from "react-hook-form";
function Signup() {
const { register, handleSubmit, formState: { errors } } = useForm();
function onSubmit(data) {
console.log("submit", data);
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("name", { required: "Name is required" })} />
{errors.name && <p>{errors.name.message}</p>}
<input
type="email"
{...register("email", {
required: "Email is required",
pattern: { value: /^\S+@\S+\.\S+$/, message: "Invalid email" }
})}
/>
{errors.email && <p>{errors.email.message}</p>}
<button>Sign up</button>
</form>
);
} Why It’s Nicer
- No re-render on every keystroke — the library uses uncontrolled refs internally
- Validation declarations live with the fields
- Error messages and dirty/touched states for free
- Easy integration with schema validators (Zod, Yup)
With a Schema (Zod)
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
const schema = z.object({
name: z.string().min(1, "Name is required"),
email: z.string().email("Invalid email"),
age: z.coerce.number().min(18, "Must be 18+"),
});
function Signup() {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
});
// ... same as before
} The schema is the single source of truth for shape AND validation.
When To Skip
For one input or two, useState is fine. The library shines when
you have a handful of fields, mixed validation rules, and want
clean code at the call site.
Up Next
How to write tests.
Testing →