Unlike Formik's typically controlled-input approach, React Hook Form registers each input using refs internally via the spread {...register('fieldName')}, meaning individual keystrokes don't trigger a re-render of the whole form the way updating controlled state on every change does, which can meaningfully improve performance for very large forms. The handleSubmit function wraps your own submit handler, running validation first and only calling your handler with the current form values if validation passes, and validation rules can be specified inline via register's options or through a schema-validation library like Yup or Zod via a resolver.
1Understanding React Hook Form
Unlike Formik's typically controlled-input approach, React Hook Form registers each input using refs internally via the spread {...register('fieldName')}, meaning individual keystrokes don't trigger a re-render of the whole form the way updating controlled state on every change does, which can meaningfully improve performance for very large forms. The handleSubmit function wraps your own submit handler, running validation first and only calling your handler with the current form values if validation passes, and validation rules can be specified inline via register's options or through a schema-validation library like Yup or Zod via a resolver.
React Hook Form's ref-based registration means most individual keystrokes don't trigger a React re-render of the whole form at all, unlike a fully controlled Formik-style form, which is exactly why it tends to perform noticeably better on very large forms with many fields.
import { useForm } from 'react-hook-form';
function LoginForm() {
const { register, handleSubmit } = useForm();
const onSubmit = (data) => console.log('Submitted:', data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email', { required: true })} />
<button type="submit">Log In</button>
</form>
);
}2Practical Example
Here is a real-world application of React Hook Form showing how it is used in production React code.
import { useForm } from 'react-hook-form';
function LoginForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register('email', { required: 'Email is required' })} />
{errors.email && <span>{errors.email.message}</span>}
</form>
);
}3Best Practices
Follow these guidelines when working with React Hook Form:
1. Register inputs via {...register('fieldName', validationRules)} rather than manually wiring controlled state and onChange handlers for each field
2. Wrap your actual submit logic in handleSubmit(), letting it run validation first and only invoke your function once the form is genuinely valid
3. Use a schema-validation library like Zod or Yup via a resolver for complex validation, rather than scattering many individual inline validation rules across each register() call
Tip: React Hook Form's ref-based registration means most individual keystrokes don't trigger a React re-render of the whole form at all, unlike a fully controlled Formik-style form, which is exactly why it tends to perform noticeably better on very large forms with many fields.
import { useForm } from 'react-hook-form';
function LoginForm() {
const { register, handleSubmit } = useForm();
const onSubmit = (data) => console.log('Submitted:', data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email', { required: true })} />
<button type="submit">Log In</button>
</form>
);
}