OnBlur и onChange валидация

Валидация форм в современных фронтенд-приложениях строится вокруг событийной модели ввода данных, где ключевую роль играют моменты изменения значения поля и потеря фокуса. В связке с React Hook Form и схемной валидацией через Yup особое значение приобретает выбор стратегии запуска проверки: onChange и onBlur определяют баланс между отзывчивостью интерфейса и нагрузкой на систему валидации.

Событие onChange возникает при каждом изменении значения поля ввода. Это делает его максимально чувствительным механизмом, позволяющим реагировать на ввод в реальном времени. Однако такая чувствительность приводит к потенциальной избыточности: каждая клавиша инициирует цепочку обновлений состояния и повторную валидацию.

Событие onBlur срабатывает при потере фокуса элементом формы. В отличие от onChange, оно агрегирует изменения, откладывая проверку до завершения ввода. Это снижает количество вызовов валидатора и уменьшает визуальный шум ошибок, но увеличивает задержку обратной связи.

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

Роль React Hook Form и интеграции через resolver

React Hook Form использует неконтролируемую модель форм с минимальным количеством перерендеров. Это делает его особенно чувствительным к частоте триггеров валидации.

Интеграция со схемами валидации реализуется через слой адаптации — resolver. В экосистеме используется пакет @hookform/resolvers, который связывает внешние схемы (например, Yup) с внутренним механизмом проверки RHF.

Роль resolver заключается в следующем:

  • преобразование значений формы в формат, ожидаемый схемой
  • запуск валидации
  • нормализация ошибок в структуру, понятную React Hook Form
  • возврат результата валидации в систему состояния формы

Таким образом, Yup не используется напрямую внутри компонентов формы, а выступает как декларативный слой описания правил.

Yup как декларативная схема валидации

Yup предоставляет объектную модель описания данных, где каждое поле сопровождается цепочкой правил:

  • тип значения
  • обязательность
  • ограничения длины
  • регулярные выражения
  • кастомные проверки

Пример схемы:

import * as Yup from "yup";

const schema = Yup.object({
  email: Yup.string()
    .email("Некорректный формат")
    .required("Поле обязательно"),
  password: Yup.string()
    .min(8, "Минимум 8 символов")
    .required("Поле обязательно"),
});

Эта схема не зависит от UI-слоя и может использоваться в различных контекстах: клиентская валидация, серверная проверка, тестирование.

YupResolver как мост между схемой и формой

@hookform/resolvers обеспечивает адаптацию Yup-схемы для React Hook Form.

Механизм работы включает:

  1. получение текущих значений формы

  2. передача их в Yup-схему

  3. выполнение синхронной или асинхронной валидации

  4. преобразование ошибок Yup в формат RHF:

    {
      fieldName: {
        type: "validationType",
        message: "Ошибка"
      }
    }
  5. возврат результата в React Hook Form

Этот слой абстракции позволяет не писать ручную валидацию и не синхронизировать правила между UI и бизнес-логикой.

Стратегии запуска валидации: onChange, onBlur, onSubmit

React Hook Form поддерживает несколько режимов валидации, которые напрямую влияют на момент вызова resolver.

Валидация onChange

Режим onChange активирует проверку при каждом изменении значения поля.

Характерные особенности:

  • мгновенная обратная связь
  • высокая частота вызовов Yup
  • риск деградации производительности на сложных схемах
  • повышенная нагрузка при вложенных объектах формы

Применяется в случаях, где критична моментальная проверка корректности, например:

  • форматирование email
  • проверка масок
  • числовые ограничения

Пример конфигурации:

const form = useForm({
  resolver: yupResolver(schema),
  mode: "onChange",
});

Валидация onBlur

Режим onBlur запускает проверку только при потере фокуса поля.

Особенности:

  • снижение количества вызовов resolver
  • уменьшение “мигания” ошибок
  • более стабильный интерфейс ввода
  • задержка обратной связи до завершения ввода

Пример:

const form = useForm({
  resolver: yupResolver(schema),
  mode: "onBlur",
});

Данный режим особенно эффективен для длинных форм, где каждое поле имеет сложные правила.

Гибридный режим (onBlur + onChange после касания поля)

Часто используется комбинация поведения:

  • первичная проверка на blur
  • последующая проверка на change после первого взаимодействия

В React Hook Form это достигается через конфигурацию:

const form = useForm({
  resolver: yupResolver(schema),
  mode: "onBlur",
  reValidateMode: "onChange",
});

Здесь:

  • mode задаёт первичный триггер
  • reValidateMode определяет поведение после появления ошибки

Взаимодействие событий с resolver-циклом

Каждый триггер (onChange или onBlur) запускает следующий цикл:

  1. обновление значения поля
  2. формирование snapshot состояния формы
  3. вызов resolver (Yup)
  4. получение результата валидации
  5. обновление ошибок
  6. перерендер затронутых компонентов

При onChange этот цикл повторяется многократно в короткие интервалы времени, что делает оптимизацию критически важной.

Производительность и оптимизация

Использование Yup в связке с частыми событиями требует учёта стоимости валидации.

Факторы нагрузки:

  • сложные вложенные схемы
  • кастомные test функции
  • асинхронные проверки
  • трансформации данных (transform)

При режиме onChange важно учитывать:

  • мемоизацию схемы (избегание пересоздания объекта)
  • разделение формы на изолированные поля
  • использование shouldUnregister: false для стабильности состояния
  • ограничение глубины наблюдаемых структур

В режиме onBlur основная нагрузка переносится на редкие, но более крупные вызовы, что делает поведение более предсказуемым.

Сравнение стратегий валидации

onChange

  • минимальная задержка реакции
  • высокая частота вычислений
  • возможная перегрузка UI при сложных схемах

onBlur

  • сниженная нагрузка
  • более стабильное отображение ошибок
  • задержка обратной связи

onSubmit

  • единичная валидация
  • отсутствие промежуточных ошибок
  • максимальная производительность, но минимальная интерактивность

Поведение ошибок в разных режимах

Yup возвращает структурированные ошибки, которые затем нормализуются resolver’ом.

При onChange ошибки могут появляться и исчезать динамически, что требует аккуратного UI-представления:

  • предотвращение “мерцания” сообщений
  • фильтрация частичных состояний

При onBlur ошибки фиксируются после завершения ввода, что упрощает визуальную модель состояния формы.

Кастомные сценарии валидации

В реальных приложениях часто используется смешанный подход:

  • onChange для полей с форматированием (телефон, email)
  • onBlur для текстовых полей (имя, адрес)
  • onSubmit как финальный барьер

Также встречаются сценарии ручного управления:

trigger("fieldName");

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

Ошибки проектирования валидации

Распространённые проблемы:

  • использование onChange для тяжёлых Yup-схем без оптимизации
  • дублирование логики в UI и схеме
  • пересоздание схемы на каждый рендер
  • отсутствие разделения режимов reValidateMode
  • чрезмерное количество кастомных тестов

Особенно критично сочетание сложного Yup.object().shape() с режимом onChange без мемоизации.

Поведение resolver в асинхронных сценариях

Yup поддерживает асинхронные проверки через test, что влияет на поведение onChange:

  • возможны задержки между вводом и результатом
  • порядок результатов должен быть синхронизирован с последним состоянием формы
  • React Hook Form предотвращает race conditions через внутренние механизмы контроля версии состояния

Влияние архитектуры формы на выбор стратегии

Формы делятся на:

  • простые (1–5 полей)
  • средние (до 20 полей)
  • сложные (динамические списки, вложенные структуры)

Для простых форм допустим onChange без ограничений.

Для сложных форм предпочтительнее:

  • onBlur как основной режим
  • onChange как вторичный (reValidateMode)
  • частичная валидация через trigger

Взаимодействие onBlur и onChange в связке с resolver-архитектурой формирует основу предсказуемой и масштабируемой модели валидации, где Yup выступает декларативным источником правил, React Hook Form управляет состоянием, а @hookform/resolvers связывает оба слоя в единую систему исполнения.