Управление формами в React традиционно связано с балансом между контролируемыми и неконтролируемыми компонентами. Библиотека React Hook Form строится вокруг идеи минимизации количества перерендеров и делегирования большей части работы нативным возможностям DOM.
Ключевой принцип заключается в том, что значения полей не хранятся в состоянии React на каждый ввод символа. Вместо этого используется регистрация ссылок на DOM-элементы и извлечение значений по необходимости.
React Hook Form по умолчанию опирается на неконтролируемые компоненты. Это означает, что:
refТакой подход уменьшает количество ререндеров и повышает производительность форм с большим количеством полей.
Каждое поле формы должно быть зарегистрировано через функцию
register. Это связывает input с системой управления
формой.
import { useForm } from "react-hook-form";
const Form = () => {
const { register, handleSubmit } = useForm();
const onSub mit = (data) => {
console.log(data);
};
return (
<form onSub mit={handleSubmit(onSubmit)}>
<input {...register("username")} />
<input type="password" {...register("password")} />
<button type="submit">Отправить</button>
</form>
);
};
Регистрация позволяет библиотеке отслеживать значения без
необходимости управлять состоянием через useState.
Хук useForm является ядром библиотеки. Он возвращает
набор методов, управляющих всей логикой формы.
register — привязка полейhandleSubmit — обработка отправки формыwatch — наблюдение за значениямиsetValue — программное изменение значенияgetValues — получение текущих данныхreset — сброс формыcontrol — объект для интеграции с контролируемыми
компонентамиconst {
register,
handleSubmit,
watch,
setValue,
getValues,
reset,
control
} = useForm();
Функция handleSubmit инкапсулирует валидацию и сбор
данных перед вызовом пользовательского обработчика.
const onSub mit = (data) => {
console.log(data);
};
<form onSub mit={handleSubmit(onSubmit)}>
Механизм работы:
React Hook Form поддерживает декларативную валидацию через параметры
register.
<input
{...register("email", {
required: "Email обязателен",
pattern: {
value: /\S+@\S+\.\S+/,
message: "Неверный формат email"
}
})}
/>
register("username", {
validate: (value) => value !== "admin" || "Недопустимое имя"
});
Ошибки доступны через formState.errors.
const {
register,
handleSubmit,
formState: { errors }
} = useForm();
Использование:
{errors.email && <span>{errors.email.message}</span>}
Каждое поле содержит собственный объект ошибки, если правило валидации не прошло.
Функция watch позволяет отслеживать изменения полей.
const password = watch("password");
Можно наблюдать:
const formValues = watch();
Используется для установки значения поля вручную.
setValue("username", "Ivan");
Позволяет получить текущие значения без подписки.
const values = getValues();
Метод reset возвращает форму в начальное состояние.
reset();
Можно задать новые значения:
reset({
username: "default"
});
Некоторые UI-библиотеки не работают с ref, поэтому
используется Controller.
import { Controller } from "react-hook-form";
<Controller
name="select"
control={control}
render={({ field }) => (
<sel ect {...field}>
<option value="a">A</option>
<option value="b">B</option>
</select>
)}
/>
Controller связывает внешние компоненты с системой
формы.
React Hook Form минимизирует перерендеры за счёт нескольких механизмов:
ref вместо stateЭто особенно важно для:
Для динамических списков используется useFieldArray.
import { useFieldArray } fr om "react-hook-form";
const { fields, append, remove } = useFieldArray({
control,
name: "users"
});
fields.map((field, index) => (
<input {...register(`users.${index}.name`)} />
));
Операции:
React Hook Form хорошо интегрируется с TypeScript через generics.
type FormValues = {
username: string;
age: number;
};
const { register } = useForm<FormValues>();
Это обеспечивает:
Валидация может быть асинхронной:
register("username", {
validate: async (value) => {
const res = await fetch(`/check?name=${value}`);
return res.ok || "Имя занято";
}
});
Особенности:
React Hook Form поддерживает интеграцию с схемами через резолверы.
import { zodResolver } from "@hookform/resolvers/zod";
const schema = z.object({
username: z.string().min(3)
});
const { register } = useForm({
resolver: zodResolver(schema)
});
import { yupResolver } from "@hookform/resolvers/yup";
В крупных приложениях используется FormProvider.
const methods = useForm();
<FormProvider {...methods}>
<ChildForm />
</FormProvider>
Внутри:
const { register } = useFormContext();
Это позволяет избегать prop drilling.
Основные техники:
memo для компонентов полейwatchuseFormState для локальных
обновленийconst { errors } = useFormState({
control,
name: "email"
});
Можно программно управлять фокусом:
setFocus("username");
Это используется для:
React Hook Form работает через подписку на события DOM:
Это снижает необходимость ручного управления состоянием и синхронизацией.
Поддерживаются вложенные объекты:
register("user.address.city");
И массивы:
register("items.0.name");
Форма автоматически формирует структуру объекта:
{
user: {
address: {
city: ""
}
}
}