Validating Forms with React Hook Form
Forms with React Hook Form
~11 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
Our ReviewForm.jsx from the last chapter works, but with larger forms (many fields, more complex rules) the manual approach quickly becomes repetitive. React Hook Form is by far the most popular library for automating this.
Installation
npm install react-hook-formWhy React Hook Form (and not just more custom code)?
- Fewer re-renders: React Hook Form tracks field values internally via uncontrolled references (see chapter 13) instead of
useStateper keystroke – noticeably faster on large forms. - Built-in validation rules: "required", "minLength", custom validator functions – without writing every rule yourself.
- Less code: no
useStateper field, no manualonChangehandling.
Rebuilding ReviewForm.jsx
Replace the entire content of src/components/ReviewForm.jsx:
import { useForm } from 'react-hook-form';
function ReviewForm({ onSubmitReview }) {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm({
defaultValues: { name: '', rating: 5, comment: '' },
});
function onValid(values) {
onSubmitReview(values);
reset();
}
return (
<form onSubmit={handleSubmit(onValid)} className="review-form">
<div className="form-field">
<label htmlFor="name">Name</label>
<input
id="name"
{...register('name', { required: 'Please enter your name.' })}
/>
{errors.name && <p className="form-error">{errors.name.message}</p>}
</div>
<div className="form-field">
<label htmlFor="rating">Rating</label>
<select id="rating" {...register('rating')}>
{[5, 4, 3, 2, 1].map((star) => (
<option key={star} value={star}>{star} {star === 1 ? 'star' : 'stars'}</option>
))}
</select>
</div>
<div className="form-field">
<label htmlFor="comment">Comment</label>
<textarea
id="comment"
{...register('comment', {
minLength: { value: 10, message: 'The comment must be at least 10 characters long.' },
})}
/>
{errors.comment && <p className="form-error">{errors.comment.message}</p>}
</div>
<button type="submit">Submit review</button>
</form>
);
}
export default ReviewForm;Understanding register(): the heart of the library
{{...register('name', {{ required: '...' }})}} is the central idea: register() returns an object with exactly the props an <input> needs to register itself with React Hook Form (among others name, onChange, onBlur, ref) – the spread operator {{...register(...)}} passes all of these through automatically as props, without you having to write them out one by one.
formState: {{ errors }} automatically holds the matching error messages per field name after a failed validation attempt – errors.name.message is exactly the string you passed to required.
| Chapter 14 (manual) | React Hook Form |
|---|---|
useState per field + a custom validate() function | register('fieldname', {{ rules }}) handles state AND validation |
Write an onChange handler manually for each field | wired automatically via register() |
Call event.preventDefault() manually | handleSubmit(onValid) handles this automatically, only calls onValid with VALID data |
Tipp: Both approaches – manual validation and React Hook Form – are valid, common patterns in real projects. Small, simple forms (one or two fields) are often just as fast written manually; once a form grows, React Hook Form pays off noticeably.