Работа с YupResolver в экосистеме React Hook Form строится вокруг
нескольких ключевых пакетов: react-hook-form,
@hookform/resolvers и yup. Каждый из них
выполняет строго определённую роль: управление состоянием формы,
адаптация валидаторов и декларативное описание схем валидации
соответственно.
Установка через npm:
npm install react-hook-form yup @hookform/resolvers
Аналогичная установка через yarn:
yarn add react-hook-form yup @hookform/resolvers
При использовании pnpm:
pnpm add react-hook-form yup @hookform/resolvers
Версионная совместимость имеет значение, особенно в контексте
TypeScript-проектов. @hookform/resolvers синхронизируется с
версиями React Hook Form, поэтому при обновлении одной части стека
требуется проверка остальных зависимостей.
YupResolver выступает связующим адаптером между
декларативной схемой валидации Yup и механизмом валидации React Hook
Form.
Основная задача заключается в преобразовании схемы Yup в формат, понятный системе валидации формы. Это позволяет:
Механизм работы основан на функции-обёртке, возвращающей асинхронный резолвер:
import { yupResolver } from '@hookform/resolvers/yup';
Перед подключением резолвера формируется схема валидации с использованием Yup.
Простейший пример описания структуры данных:
import * as yup from 'yup';
const schema = yup.object({
username: yup.string().required('Поле обязательно'),
email: yup.string().email('Некорректный email').required('Обязательное поле'),
age: yup.number().min(18, 'Минимальный возраст 18 лет')
});
Каждое поле схемы описывается как самостоятельное правило. Yup поддерживает цепочки методов, что позволяет формировать сложные правила без внешней логики.
Интеграция осуществляется через хук useForm, где
резолвер передаётся в конфигурацию формы.
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
Далее выполняется связывание схемы и формы:
const schema = yup.object({
username: yup.string().required(),
email: yup.string().email().required()
});
const form = useForm({
resolver: yupResolver(schema)
});
В этом контексте resolver становится промежуточным
слоем, который обрабатывает значения формы перед их попаданием в логику
сабмита.
При каждом изменении состояния формы или при попытке отправки данных
React Hook Form передаёт текущие значения в
yupResolver.
Процесс включает несколько этапов:
Ошибки преобразуются в структуру:
{
fieldName: {
type: "validation-type",
message: "Описание ошибки"
}
}
При использовании TypeScript важным аспектом становится синхронизация типов между схемой и формой.
Yup предоставляет механизм вывода типов через
InferType:
import * as yup from 'yup';
const schema = yup.object({
username: yup.string().required(),
email: yup.string().email().required()
});
type FormData = yup.InferType<typeof schema>;
Далее тип передаётся в useForm:
const form = useForm<FormData>({
resolver: yupResolver(schema)
});
Это позволяет добиться строгой типизации значений формы и исключить несоответствия между UI и схемой валидации.
Yup поддерживает асинхронные проверки через метод test,
что позволяет интегрировать серверные проверки или обращения к внешним
источникам.
Пример проверки уникальности:
const schema = yup.object({
username: yup.string().test(
'check-username',
'Имя уже занято',
async (value) => {
const response = await fetch(`/api/check-username?value=${value}`);
const data = await response.json();
return data.available;
}
)
});
YupResolver корректно обрабатывает промисы, возвращаемые схемой, и ожидает завершения всех асинхронных операций перед формированием результата.
React Hook Form поддерживает различные режимы триггера валидации:
onSubmit — проверка при отправке формы;onChange — проверка при каждом изменении поля;onBlur — проверка при потере фокуса;all — комбинация поведения.Пример конфигурации:
const form = useForm({
resolver: yupResolver(schema),
mode: 'onChange'
});
Выбор режима влияет на количество вызовов YupResolver и, соответственно, на производительность валидации.
Yup поддерживает передачу контекста, который может использоваться внутри правил валидации.
Пример использования:
const schema = yup.object({
password: yup.string().required(),
confirmPassword: yup.string().oneOf(
[yup.ref('password')],
'Пароли не совпадают'
)
});
Дополнительно возможно использование context в
резолвере:
useForm({
resolver: yupResolver(schema, { context: { role: 'admin' } })
});
Внутри схемы контекст доступен через
this.options.context.
YupResolver возвращает ошибки в стандартизированном виде, однако структура может быть трансформирована с помощью дополнительных опций.
Некоторые сценарии требуют нормализации сообщений или изменения структуры вложенности. В таких случаях применяется промежуточная обработка результатов:
const resolver = yupResolver(schema, {
abortEarly: false
});
Опция abortEarly: false позволяет собрать все ошибки
сразу, а не останавливаться на первой найденной.
Yup корректно обрабатывает сложные структуры данных, включая вложенные объекты и массивы.
Пример:
const schema = yup.object({
user: yup.object({
name: yup.string().required(),
contacts: yup.array().of(
yup.object({
type: yup.string().required(),
value: yup.string().required()
})
)
})
});
YupResolver преобразует вложенные ошибки в формат, совместимый с React Hook Form, сохраняя путь к каждому полю.
При работе с большими формами значительное влияние оказывает частота вызовов резолвера и сложность схемы.
Основные факторы оптимизации:
useMemo для схемы;Пример мемоизации схемы:
const schema = useMemo(() => yup.object({
username: yup.string().required(),
email: yup.string().email().required()
}), []);
Это предотвращает пересоздание схемы при каждом рендере компонента.
Динамические формы, где количество полей изменяется во время выполнения, требуют корректного описания массивов в Yup.
Пример:
const schema = yup.object({
fields: yup.array().of(
yup.object({
value: yup.string().required()
})
)
});
React Hook Form синхронизирует изменения структуры формы с результатами YupResolver, обеспечивая корректную валидацию даже при добавлении или удалении элементов массива.
При вызове reset React Hook Form сбрасывает состояние,
однако YupResolver не выполняет дополнительной логики, так как валидация
запускается только при триггере событий формы.
form.reset({
username: '',
email: ''
});
После сброса данные проходят повторную проверку при следующем взаимодействии с формой, в зависимости от выбранного режима валидации.