В контексте использования React Hook Form одной из наиболее распространённых схем валидации остаётся связка с Yup через YupResolver. Несмотря на удобство декларативного описания схем и интеграции с формами, именно производительность этой связки часто становится узким местом в приложениях с большим количеством полей, динамическими формами или частыми пересчётами состояния.
Основной источник затрат — повторная компиляция и выполнение схемы
валидации при каждом изменении значения поля. При работе с YupResolver
каждый ввод пользователя может инициировать полный прогон схемы или её
части, в зависимости от режима валидации (onChange,
onBlur, onSubmit).
Особенно заметны следующие факторы:
Глубокие схемы валидации При вложенных объектах и массивах Yup вынужден рекурсивно обходить структуру данных. В случае сложных форм (например, многошаговые анкеты или конструкторы) это приводит к экспоненциальному росту времени проверки.
Отсутствие мемоизации схемы по умолчанию Хотя схема Yup может быть объявлена вне компонента, на практике часто допускается её пересоздание внутри рендера. Это приводит к повторной инициализации resolver-а и лишним вычислениям.
Частые триггеры валидации Режим
mode: onChange вызывает перерасчёт состояния при каждом
вводе символа. При тяжёлой схеме даже простой ввод текста становится
дорогостоящей операцией.
Сериализация и десериализация данных YupResolver вынужден преобразовывать данные формы в формат, совместимый со схемой, что добавляет дополнительный слой обработки между React Hook Form и Yup.
Рост количества контролируемых полей приводит к нелинейному увеличению нагрузки. В простых формах разница почти незаметна, однако при десятках или сотнях полей проявляются следующие эффекты:
formState.Особенно критично это проявляется при использовании
watch для подписки на изменения всей формы, что фактически
заставляет React Hook Form реагировать на каждое изменение структуры
данных.
YupResolver создаётся как функция-обёртка над схемой Yup. При каждом вызове она:
Проблема возникает не в самой архитектуре, а в частоте вызова. При
интенсивных обновлениях формы resolver становится «горячей точкой»
выполнения, особенно если схема содержит кастомные валидаторы
(test, when, условные зависимости).
Кастомные проверки внутри Yup (test) часто содержат
синхронный код, который:
При использовании YupResolver такие функции вызываются многократно, иногда даже для неизменённых полей, если пересчёт схемы затрагивает родительский объект.
Дополнительная проблема — условная валидация через when.
Она требует повторной оценки зависимостей между полями, что увеличивает
стоимость каждого прохода проверки.
React Hook Form предоставляет несколько режимов валидации, и выбор режима напрямую влияет на нагрузку:
onChange — максимальная нагрузка, так как триггерится
часто;onBlur — средняя нагрузка, но с накоплением затрат при
массовом фокусировании;onSubmit — минимальная нагрузка, но откладывает
проверку до конца.При использовании YupResolver в режиме onChange каждая
правка поля может запускать полный цикл проверки схемы, включая все
зависимые поля.
Массивы (array().of(...)) являются одним из самых
дорогих типов структур в Yup. При изменении одного элемента массива:
В формах с динамическими списками (например, добавление/удаление строк) это становится критическим фактором деградации производительности.
React Hook Form оптимизирует рендеры через подписки, однако при использовании YupResolver:
formState.errors обновляется целиком;Это создаёт каскадный эффект: даже если вычисления Yup быстрые, React-часть приложения может становиться узким местом.
Одним из ключевых факторов стабилизации производительности является вынесение схемы из компонента. Однако даже в этом случае остаются проблемы:
При добавлении асинхронных валидаторов (например, проверка уникальности имени через API):
Это усиливает нагрузку не только на клиент, но и на серверную часть.
При увеличении масштаба формы до корпоративных сценариев (CRM, админ-панели, конструкторы):
Особенно заметно это в формах с:
Снижение проблем производительности достигается не одной настройкой, а комбинацией архитектурных решений:
shouldUnregister для удаления неактивных
полей;onBlur или
onSubmit;useMemo;watch в пользу локальных
подписок;test и when в Yup-схемах.Каждое из этих решений снижает нагрузку, но наиболее значимый эффект даёт сокращение частоты вызова resolver-а и уменьшение глубины схемы.