Гид по технологиям

React Hook Form: формы в React быстро и надёжно

5 min read Frontend Обновлено 14 Dec 2025
React Hook Form: формы в React быстро и надёжно
React Hook Form: формы в React быстро и надёжно

Сфокусированный крючок из нержавеющей стали

Введение

Создание форм в React часто выглядит просто, но при росте требований код стремительно усложняется. React Hook Form уменьшает количество кода, улучшает производительность и упрощает тестирование. Коротко: useForm управляет состоянием, register связывает поля, handleSubmit обрабатывает отправку.

Важно: React Hook Form — это не контроллер UI. Он оставляет за вами рендер полей и стили. Он просто даёт удобный и быстрый способ управлять данными формы и валидацией.

Установка React Hook Form

Установите библиотеку через npm или yarn. В терминале выполните одну из команд:

npm install react-hook-form

или

yarn add react-hook-form

Примечание: используйте ту же версию React, которая поддерживается в вашей кодовой базе. React Hook Form хорошо работает с React 16.8+ (hooks).

Создание формы с помощью useForm

Хук useForm даёт объект с методами и состоянием формы. Набор минимальных шагов:

  • подключить useForm
  • зарегистрировать поля через register
  • обернуть отправку в handleSubmit

Простой пример формы:

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 привязывает поле к внутреннему хранилищу React Hook Form. handleSubmit валидирует данные и вызывает onSubmit с объектом значений.

Валидация через register

register принимает вторым аргументом объект с правилами валидации. Это простой способ описать ограничения прямо в поле.

Пример с обязательными полями и ограничением длины пароля:

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 — кастомная функция проверки

min и max

min и max полезны для input type=”number”. Пример:

Значение должно быть не меньше 18 и не больше 35.

minLength

minLength задаёт минимальную длину строки:

pattern и validate

pattern применяет регулярное выражение. validate принимает функцию, возвращающую true или строку с сообщением об ошибке.


 value <= 12 || 'Значение должно быть ≤ 12' })} />

Совет: при использовании pattern указывайте понятные сообщения об ошибках через validate или в UI.

Обработка ошибок

useForm предоставляет 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 (
    
{errors.firstname && Пожалуйста, введите имя} {errors.age?.type === 'max' && Вы слишком взрослые для этого сайта} {errors.age?.type === 'min' && Вы слишком молоды для этого сайта}
) } export default Form

Важно: messages лучше хранить отдельно для локализации.

Практические рекомендации и лучшие практики

  • Используйте контролируемые компоненты только там, где это необходимо (например, кастомные UI-компоненты). В остальных случаях отдавайте предпочтение register — это быстрее.
  • Выносите правила валидации в отдельные функции/модули для повторного использования и тестирования.
  • Для больших форм используйте useFieldArray для динамических списков полей.
  • Локализуйте сообщения об ошибках.
  • Покрывайте формы юнит- и интеграционными тестами.

Важно: не смешивайте state формы и глобальный state без явной причины. Храните форму локально, чтобы избежать лишних перерендеров.

Когда React Hook Form не подходит

  • Если у вас уже есть сложная логика синхронизации форм с сервером и глобальным хранилищем, и вы полагаетесь на централизованный state (например, Redux), может быть проще использовать контролируемые компоненты.
  • Если у вас специфичные UI-библиотеки с собственными контроллерами, понадобится адаптер или контроллируемые обёртки.

Альтернативы:

  • Formik — более «полнофункциональная» библиотека с контролируемыми полями.
  • Final Form — гибкая система с плагинами и подписками.

Сравнение подходов (короткая матрица)

  • register (React Hook Form): низкий оверхед, меньше перерендеров, проще тестировать.
  • контролируемые поля: точный контроль над локальным состоянием, удобнее при тесной интеграции с UI-риверами.
  • Formik: более подробный API, может быть проще для новичков, но чаще вызывает перерендеры.

Доступность и безопасность

  • Всегда используйте семантические теги
  • Для сообщений об ошибках связывайте aria-describedby с id элемента ошибки.
  • Не храните в форме чувствительные данные дольше, чем нужно. Очищайте поля после отправки, если это требуется.
  • Проверяйте данные на сервере независимо от клиентской валидации.

Тесты и критерии приёмки

Критерии приёмки для формы:

  • Форма рендерится с ожидаемыми полями.
  • Валидация срабатывает на пустые обязательные поля.
  • Появляется корректное сообщение об ошибке для каждого правила.
  • При валидных данных вызывается callback onSubmit с правильным объектом значений.
  • Поле с типом number принимает только числа и соблюдает min/max.

Минимальные тесты (Jest/React Testing Library):

  • Рендер формы и проверка начальных элементов.
  • Ввод некорректных данных и проверка сообщений об ошибках.
  • Ввод корректных данных и проверка вызова onSubmit.

Чеклист роли разработчика

  • Разработчик интерфейса:

    • Проверил доступность (labels, aria)
    • Подготовил UI-компоненты для интеграции с register
  • Backend-разработчик:

    • Подтвердил контракт данных
    • Обеспечил серверную валидацию
  • QA-инженер:

    • Написал тесты сценариев валидации
    • Проверил поведение при ошибках сети

Примеры расширенных сценариев

  1. Динамический массив полей (useFieldArray): используйте, когда пользователю нужно добавлять/удалять записи.
  2. Интеграция с UI-библиотеками: применяйте Controller из react-hook-form для компонент, которые не поддерживают ref или onChange в стандартном виде.

Пример использования Controller (кратко):

import { useForm, Controller } from 'react-hook-form'
import Select from 'react-select'

function MyForm() {
  const { control, handleSubmit } = useForm()
  const onSubmit = data => console.log(data)

  return (