В связке с библиотекой форм React Hook Form активно используются резолверы, обеспечивающие унифицированный интерфейс для различных систем валидации. Одним из таких адаптеров является Vest resolver, предназначенный для интеграции с Vest.
Vest реализует подход, вдохновлённый тестовыми фреймворками: правила валидации оформляются как набор проверок, группируемых в «сессии». Resolver выступает мостом между результатом выполнения этих проверок и форматом ошибок, который ожидает React Hook Form.
Vest resolver выполняет три ключевые функции:
1. Запуск сессии валидации Vest Передача данных
формы в функцию vest-схемы и запуск набора правил.
2. Агрегация результатов Vest возвращает структурированный результат, содержащий информацию о проваленных проверках.
3. Преобразование в формат React Hook Form Результат конвертируется в объект вида:
{
values: Record<string, any>,
errors: Record<string, { type: string; message: string }>
}
Этот формат строго соответствует контракту резолверов React Hook Form.
Для использования Vest resolver требуется базовая связка:
npm install react-hook-form vest @hookform/resolvers
Или:
yarn add react-hook-form vest @hookform/resolvers
Пакет @hookform/resolvers предоставляет адаптеры для
различных библиотек валидации, включая Yup, Zod, Joi и Vest.
Vest строится вокруг функции vest.create, которая
определяет набор правил:
import { create, test, enforce } from 'vest';
const loginSuite = create((data = {}) => {
test('email', 'Email обязателен', () => {
enforce(data.email).isNotEmpty();
});
test('email', 'Некорректный email', () => {
enforce(data.email).matches(/.+@.+\..+/);
});
test('password', 'Пароль слишком короткий', () => {
enforce(data.password).longerThan(6);
});
});
Каждый test привязывается к конкретному полю формы. Это
ключевой момент для дальнейшего маппинга в ошибки React Hook Form.
Основной механизм подключения реализуется через
vestResolver:
import { useForm } from 'react-hook-form';
import { vestResolver } from '@hookform/resolvers/vest';
import { loginSuite } from './validation';
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: vestResolver(loginSuite),
});
Resolver автоматически вызывает loginSuite, передавая
туда данные формы, и преобразует результат в стандартный формат
ошибок.
Vest формирует ошибки в виде массива тестов, но React Hook Form ожидает объект с ключами полей.
Пример внутреннего результата Vest:
{
"valid": false,
"tests": [
{
"field": "email",
"message": "Email обязателен"
},
{
"field": "password",
"message": "Пароль слишком короткий"
}
]
}
После обработки resolver преобразует это в:
{
email: { type: 'manual', message: 'Email обязателен' },
password: { type: 'manual', message: 'Пароль слишком короткий' }
}
Vest поддерживает множественные проверки одного поля. Resolver применяет стратегию:
Пример:
test('email', 'Email обязателен', ...)
test('email', 'Некорректный формат', ...)
В React Hook Form по умолчанию будет отображена последняя или приоритетная ошибка.
Vest поддерживает асинхронные проверки через
async test:
test('username', 'Имя уже занято', async () => {
await delay(300);
enforce(await isUsernameTaken(data.username)).isFalsy();
});
Resolver корректно обрабатывает Promise-результаты и дожидается завершения всех тестов перед возвратом результата в React Hook Form.
Vest имеет встроенный механизм оптимизации:
Resolver использует эти возможности автоматически, не требуя дополнительной настройки.
В React Hook Form различаются режимы валидации:
onSubmit — проверка при отправке формыonChange — проверка при изменении поляonBlur — проверка при потере фокусаVest resolver вызывается в каждом из режимов одинаково, однако Vest внутри может переиспользовать результаты прошлых сессий, снижая нагрузку.
Для строгой типизации рекомендуется явно описывать структуру формы:
type FormValues = {
email: string;
password: string;
};
const loginSuite = create<FormValues>((data) => {
test('email', 'Email обязателен', () => {
enforce(data.email).isNotEmpty();
});
});
React Hook Form автоматически выводит типы через
useForm<FormValues>(), обеспечивая согласованность
данных между формой и схемой валидации.
Vest позволяет формировать произвольные ошибки:
test('password', 'Слишком простой пароль', () => {
if (data.password === '123456') {
fail('Слишком распространённый пароль');
}
});
Resolver интерпретирует такие ошибки как стандартные и добавляет их в
объект errors.
Vest работает по принципу полного прогона сессии. Это означает:
Такой подход особенно полезен для сложных форм с множественными зависимостями полей.
В экосистеме @hookform/resolvers существуют
альтернативы:
Vest выделяется тем, что:
Типичные проблемы при использовании Vest resolver:
1. Несовпадение имён полей Если
test('email') не совпадает с
register('email'), ошибка не будет отображена.
2. Отсутствие возврата данных из suite Если Vest-сессия не возвращает корректный результат, resolver не сможет сформировать errors.
3. Асинхронные тесты без await внутри enforce Нарушение приводит к некорректной агрегации ошибок.
При использовании динамических полей (например, массивов через
useFieldArray в React Hook Form):
Полный цикл работы Vest resolver:
Этот цикл выполняется синхронно или асинхронно в зависимости от наличия async тестов.
Vest resolver особенно эффективен в сценариях:
В таких случаях императивная природа Vest обеспечивает большую гибкость по сравнению с чисто декларативными схемами.