DEV Community

Alex Spinov
Alex Spinov

Posted on

React Hook Form Has a Free Form Library: Build Performant Forms With Zero Re-Renders and Built-In Validation

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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)