Controlled forms in React re-render on every keystroke. Formik adds 12KB and still re-renders. You manage onChange, onBlur, error states, and touched flags manually.
What if your form library used uncontrolled inputs, never caused unnecessary re-renders, and validated with zero boilerplate?
That's React Hook Form. 8KB, zero dependencies, near-zero re-renders.
Basic Usage
import { useForm } from "react-hook-form";
interface LoginForm {
email: string;
password: string;
}
function Login() {
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<LoginForm>();
const onSubmit = async (data: LoginForm) => {
await fetch("/api/login", { method: "POST", body: JSON.stringify(data) });
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("email", { required: "Email required", pattern: { value: /\S+@\S+/, message: "Invalid email" } })} />
{errors.email && <span>{errors.email.message}</span>}
<input type="password" {...register("password", { required: "Password required", minLength: { value: 8, message: "Min 8 chars" } })} />
{errors.password && <span>{errors.password.message}</span>}
<button disabled={isSubmitting}>Log In</button>
</form>
);
}
The component re-renders only on submit or error — NOT on every keystroke. For a form with 20 fields, this is the difference between smooth and sluggish.
With Zod Validation
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
const schema = z.object({
name: z.string().min(1, "Required"),
email: z.string().email("Invalid email"),
age: z.coerce.number().min(18, "Must be 18+"),
password: z.string().min(8),
confirmPassword: z.string(),
}).refine(d => d.password === d.confirmPassword, {
message: "Passwords don't match", path: ["confirmPassword"],
});
function SignupForm() {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
});
// Same pattern — Zod handles all validation logic
}
Performance: RHF vs Formik vs Controlled
| 20-field form | React Hook Form | Formik | Controlled |
|---|---|---|---|
| Re-renders per keystroke | 0 | 1 (entire form) | 1 (entire form) |
| Mount time | 8ms | 25ms | 15ms |
| Bundle size | 8 KB | 12 KB | 0 (built-in) |
Choose React Hook Form for performance-critical forms and complex validation. Works with any UI library (MUI, Chakra, shadcn/ui).
Start here: react-hook-form.com
Need custom data extraction, scraping, or automation? I build tools that collect and process data at scale — 78 actors on Apify Store and 265+ open-source repos. Email me: Spinov001@gmail.com | My Apify Actors
Top comments (0)