Для простих форм вистачає нативних засобів React 19 (action, useActionState). Коли полів багато, є валідація з залежностями між полями, динамічні списки полів і складний UX помилок, - зручніше бібліотека.
React Hook Form керує формою через неконтрольовані поля й refs: введення не викликає рендер усієї форми. Стан помилок, «брудності», відправки - окремо.
Zod описує схему даних, з якої виходить і валідація, і тип TypeScript.
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
email: z.email('Некоректна адреса'),
password: z.string().min(8, 'Щонайменше 8 символів'),
age: z.coerce.number().int().min(18, 'Лише для повнолітніх'),
});
type FormValues = z.infer<typeof schema>;
function SignUpForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormValues>({ resolver: zodResolver(schema) });
const onSubmit = async (values: FormValues) => {
await api.signUp(values);
};
return (
<form onSubmit={handleSubmit(onSubmit)} noValidate>
<input type="email" {...register('email')} aria-invalid={!!errors.email} />
{errors.email && <p role="alert">{errors.email.message}</p>}
<input type="password" {...register('password')} />
{errors.password && <p role="alert">{errors.password.message}</p>}
<input type="number" {...register('age')} />
<button disabled={isSubmitting}>Зареєструватися</button>
</form>
);
}
Що дає поєднання:
- одна схема - і правила, і тип даних (
z.infer); схему можна використати повторно на сервері (Node) чи для перевірки відповіді API; handleSubmitвикликаєonSubmitлише з валідними даними, а при помилках ставить фокус на перше невалідне поле;- режими перевірки:
mode: 'onSubmit'(за замовчуванням),'onBlur','onChange','onTouched'.
Що варто знати:
- у Zod 4 формати рядків стали окремими функціями:
z.email()замість старогоz.string().email()(той лишився, але застарів); - значення полів - рядки: для чисел -
z.coerce.number()чиvalueAsNumberуregister; - клієнтська валідація - лише зручність. Сервер (Laravel Form Request) перевіряє все заново, а його помилки треба показати у формі через
setError; - для сторонніх компонентів (селекти, редактори) -
Controllerз React Hook Form.