Формы в React с React Hook Form — практическое руководство

Важно: краткие определения — useForm: хук для управления формой; register: регистрирует поле; handleSubmit: оборачивает функцию отправки и запускает валидацию.
Почему React Hook Form?
Создание форм в React может стать сложным и затратным по времени: управление состоянием каждого поля, валидация, отображение ошибок и производительность при большом количестве полей. React Hook Form решает эти задачи, предлагая:
- минимальные перерендеры (поля по умолчанию не контролируемые),
- простую декларативную валидацию через register,
- совместимость с UI-компонентами и кастомными компонентами,
- небольшую библиотеку с лёгким API.
Ниже — перевод, расширенные объяснения, практические советы, чек-листы и дополнительные подходы.
Установка React Hook Form
Для начала установите библиотеку через npm или yarn.
Чтобы установить через npm, выполните в терминале:
npm install react-hook-form
Чтобы установить через yarn, выполните:
yarn add react-hook-form
Совет: фиксируйте версию в package.json для воспроизводимости сборок. Если вы используете TypeScript, типы уже включены в пакет.
Создание формы с помощью useForm
Для создания формы используйте хук useForm. Он предоставляет методы и свойства для управления формой.
Пример из исходного руководства:
import React from 'react'
import { useForm } from 'react-hook-form';
function Form() {
const { register, handleSubmit } = useForm();
const onSubmit = (data) => console.log(data);
return (
)
}
export default Form;
Ключевые моменты:
- register связывает DOM-элемент с внутренним реестром форма-значений.
- handleSubmit проверяет правила валидации и вызывает onSubmit с объектом данных (например: { firstname: ‘Иван’, age: 30 }).
Пример на TypeScript (микровариант):
import React from 'react'
import { useForm, SubmitHandler } from 'react-hook-form'
type FormValues = {
firstname: string
age?: number
}
export default function FormTS() {
const { register, handleSubmit } = useForm()
const onSubmit: SubmitHandler = data => console.log(data)
return (
)
} Совет по TypeScript: используйте generic-параметр useForm
Валидация полей через register
Метод register принимает имя поля и вторым аргументом — объект правил валидации. Это простой способ задать required, min, maxLength и другие правила.
Пример из исходника:
import React from 'react'
import { useForm } from 'react-hook-form';
function Form() {
const{ register, handleSubmit } = useForm();
const onSubmit = (data) => console.log(data);
return (
)
}
export default Form;
Пояснения:
- required: поле обязательно.
- maxLength / minLength: ограничивает длину строки.
- min / max: для числовых полей задаёт диапазон.
- pattern: регулярное выражение.
- validate: произвольная функция валидатора (возвращает true или строку с ошибкой).
min & max
Правила min и max подходят для input type=’number’. Пример:
Значение должно быть >= 18 и <= 35.
minLength
minLength указывает минимальную длину строки:
pattern & validate
pattern — регулярное выражение. validate — произвольная функция.
Пример из исходника:
/^[A-Za-z]+$/}) } />
validate: (value) => value <= 12 }) } />
Примечание: при локализации форм используйте кириллические классы в паттернах, если ожидаете ввод на русском.
Совет: всегда указывайте valueAsNumber для числовых полей, если нужны числа, иначе поля приходят как строки.
Обработка ошибок в форме
React Hook Form предоставляет formState.errors — объект с ошибками по каждому полю.
Исходный пример:
import React from 'react'
import { useForm } from 'react-hook-form';
function Form() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => console.log(data);
return (
)
}
export default Form;
Для локализации сообщений замените строки на русские или подключите i18n. Пример ошибок на русском:
- Для required: «Поле обязательно»
- Для min/max: «Значение должно быть не меньше X» / «Значение должно быть не больше Y»
- Для pattern: «Некорректный формат» или более конкретное сообщение.
Совет по UX: показывайте ошибки рядом с полем, указывайте подсказки по формату и используйте aria-describedby для доступности.
Практические рекомендации и лучшие практики
- Минимизируйте контролируемые поля: используйте uncontrolled inputs и register — это повышает производительность.
- Для сложных кастомных компонентов используйте Controller из react-hook-form.
- Валидируйте синхронно и асинхронно: для проверки уникальности логина используйте async-validate (через validate возвращая промис).
- В TypeScript используйте типы формы для безопасности.
- Централизуйте сообщения об ошибках для локализации и консистентности.
- Используйте режим reValidateMode и mode в useForm (onBlur/onChange/onSubmit) в зависимости от UX.
Пример Controller для кастомного UI-компонента:
import { Controller, useForm } from 'react-hook-form'
import Select from 'react-select'
function MyForm() {
const { control, handleSubmit } = useForm()
return (
)
}Когда React Hook Form может не подойти (контрпримеры)
- Если у вас строго централизованное управление состоянием формы через Redux и нужно синхронно сериализовать каждое изменение — тогда может быть проще использовать контролируемые компоненты.
- Если вы строите крайне специфичный рабочий процесс с нестандартной сериализацией и большим набором сторонних плагинов, возможно, придётся дописать интеграцию.
- Для простых однополей формах (например, лишь один input) RHF всё ещё полезен, но может быть избыточен для очень минимальных случаев.
Альтернативные подходы
- Formik — более зрелая библиотека с удобным API, но часто требует больше перерендеров.
- Final Form — гибкая, хороша там, где нужны расширяемые пайплайны валидации.
- Нативные контролы и локальное состояние — для очень простых форм.
Выбор зависит от размеров формы, требований к производительности и предпочтений команды.
Методология: быстрый чек-лист внедрения формы (минимальный SOP)
- Определите структуру данных формы (типы полей).
- Создайте useForm с типами (если TypeScript).
- Зарегистрируйте поля через register или Controller.
- Опишите правила валидации и сообщения об ошибках.
- Добавьте обработчик handleSubmit и отправку на сервер.
- Обработайте состояние ожидания, успеха и ошибки отправки.
- Добавьте тесты (unit/e2e) и accessibility-проверки.
Чек-листы роли
Разработчик:
- Убедиться в типах формы (если TypeScript).
- Прописать правила валидации и сообщения.
- Обработать асинхронные кейсы (запрос на сервер).
- Добавить тесты и доступность.
Ревьюер:
- Проверить отсутствие лишних controlled компонентов.
- Убедиться, что ошибки локализованы и понятны.
- Проверить обработку edge-case (пустые значения, неверный формат).
Snippet: быстрый справочник правил в register (чест-шит)
- required: true | “сообщение”
- maxLength: { value: N, message: “…” }
- minLength: { value: N, message: “…” }
- min / max: { value: N, message: “…” }
- pattern: { value: /regex/, message: “…” }
- validate: value => boolean | string | Promise
Пример с сообщениями:
Тесты и критерии приёмки
Критерии приёмки:
- Поля валидируются согласно требованиям (required/min/max и т.д.).
- Ошибки отображаются корректно и доступны для скринридеров.
- При успешной отправке вызывается запрос с корректным payload.
- При ошибке сети отображается понятное сообщение.
Тест-кейсы:
- Успешная отправка с корректными данными.
- Попытка отправки с пустыми required-полями.
- Ввод за пределами min/max для чисел.
- Асинхронная проверка существования логина.
Производительность и масштабирование
- RHF снижает количество перерендеров, т.к. поля не контролируются по умолчанию.
- Для больших форм используйте оптимизацию рендеринга (React.memo, useCallback).
- Следите за частыми перерендериваниями родительских компонентов — они всё ещё могут влиять на поля.
Безопасность и конфиденциальность
- Всегда проверяйте данные на сервере, клиентская валидация — удобство для UX, но не замена серверной валидации.
- Будьте внимательны с логированием полей (пароли, PII) — не логируйте чувствительные данные в консоль на продакшне.
Интеграция с UI и локализация
- Для Material-UI, Ant Design и других библиотек используйте Controller.
- Централизуйте тексты ошибок и используйте i18n-файлы для перевода.
Пример: асинхронная валидация уникальности
{
const res = await fetch(`/api/check-username?u=${value}`)
const { available } = await res.json()
return available || 'Имя пользователя занято'
}
})} />Замечание: дебаунсьте такие проверки на стороне UI, чтобы уменьшить количество запросов.
Сравнение (краткая матрица)
- React Hook Form: лёгкая, быстрый рендер, простая интеграция с UI.
- Formik: простота API, широкое сообщество, но чаще контролируемые поля.
- Final Form: гибкость, расширяемость, подходит для сложных workflow.
Выбор: RHF — хороший компромисс между производительностью и удобством.
Decision tree (когда использовать RHF)
flowchart TD
A[Нужно ли много полей в форме?] -->|Да| B[React Hook Form]
A -->|Нет| C[Может подойти нативный state]
B --> D{Есть кастомные UI-компоненты?}
D -->|Да| E[Использовать Controller]
D -->|Нет| F[Использовать register]Краткое руководство по миграции с Formik на RHF
- Удалите внутренний state формы Formik.
- Добавьте useForm и зарегистрируйте поля.
- Замените onSubmit Formik на handleSubmit от RHF.
- Перепишите кастомные компоненты через Controller.
- Протестируйте сценарии валидации и доступности.
Заключение
React Hook Form упрощает создание надёжных и производительных форм в React. Он особенно полезен при большом количестве полей и при необходимости интегрироваться с различными UI-компонентами. При внедрении следуйте чек-листу, локализуйте сообщения об ошибках и добавьте тесты для критичных сценариев.
Ключевые преимущества: меньше повторных рендеров, лаконичный API, гибкая валидация, хорошая интеграция с TypeScript и UI-библиотеками.
Важно: всегда дополнительно валидируйте данные на сервере и не логируйте чувствительную информацию.
Сводка:
- Используйте register для простых input’ов и Controller для сложных компонентов.
- Локализуйте сообщения и следите за доступностью.
- Добавьте тесты и критерии приёмки перед релизом.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone