В React Hook Form механизм валидации отделён от ядра формы и
реализуется через абстракцию resolver. Именно он определяет, как внешняя
схема валидации интегрируется в жизненный цикл useForm,
какие данные считаются валидными и каким образом формируется объект
ошибок.
Resolver передаётся напрямую в конфигурацию useForm и
становится центральной точкой обработки данных перед их попаданием в
состояние формы.
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
const schema = yup.object({
email: yup.string().email().required(),
password: yup.string().min(6).required(),
});
const form = useForm({
resolver: yupResolver(schema),
});
useForm по умолчанию не привязан ни к одной библиотеке
валидации. Все проверки выполняются только если разработчик явно
подключает resolver. Это позволяет:
Resolver работает как промежуточный слой между значениями формы и системой React Hook Form.
yupResolver адаптирует схему Yup к интерфейсу, который
ожидает React Hook Form. На уровне исполнения он выполняет три ключевые
задачи:
Формально resolver имеет следующую сигнатуру:
(values, context, options) => Promise<{
values: object,
errors: object
}>
При использовании Yup:
resolver: yupResolver(schema)
внутри создаётся функция, которая вызывает:
schema.validate(values, { abortEarly: false })
и преобразует ошибки Yup в структуру FieldErrors.
Resolver передаётся в объект настроек useForm и
активируется на уровне всей формы.
const form = useForm({
resolver: yupResolver(schema),
mode: "onSubmit",
});
После этого каждая операция валидации (submit, change, blur — в
зависимости от mode) будет проходить через Yup.
Ключевой момент: React Hook Form больше не использует встроенные
правила required, minLength,
pattern, если подключён resolver. Все правила определяются
исключительно схемой.
При вызове handleSubmit происходит следующий
процесс:
Собираются текущие значения полей формы.
Эти значения передаются в resolver.
Yup выполняет синхронную или асинхронную проверку.
Resolver возвращает:
values — валидные данные;errors — структурированный объект ошибок.React Hook Form обновляет состояние:
formState.errors;onSubmit.Yup формирует ошибки в формате, который требует трансформации. Например:
{
email: "Email is invalid",
password: "Password must be at least 6 characters"
}
React Hook Form ожидает более сложную структуру:
{
email: {
type: "validation",
message: "Email is invalid"
},
password: {
type: "min",
message: "Password must be at least 6 characters"
}
}
yupResolver выполняет эту трансформацию автоматически,
используя информацию из ValidationError.
Несмотря на то что Yup может работать синхронно, resolver всегда
возвращает Promise. Это обеспечивает единый интерфейс для
всех валидаторов, включая асинхронные схемы.
const form = useForm({
resolver: yupResolver(schema),
});
Даже если проверка простая, React Hook Form ожидает Promise-результат, что позволяет унифицировать обработку.
Параметр mode в useForm определяет, когда
именно вызывается resolver:
onSubmit — при отправке формы;onChange — при каждом изменении значения;onBlur — при потере фокуса;all — комбинированная стратегия.useForm({
resolver: yupResolver(schema),
mode: "onChange",
});
В режиме onChange resolver может вызываться очень часто,
что делает производительность схемы важным фактором.
Некоторые сценарии требуют передачи дополнительного контекста в схему Yup. Resolver поддерживает это через второй аргумент:
useForm({
resolver: yupResolver(schema, { context: { role: "admin" } }),
});
Внутри Yup это становится доступно через
this.options.context:
yup.string().test("role-check", function (value) {
const { role } = this.options.context || {};
return role === "admin" ? true : value !== "restricted";
});
При использовании TypeScript resolver влияет на типизацию
useForm. Yup позволяет извлекать типы из схемы:
import { InferType } from "yup";
const schema = yup.object({
email: yup.string().required(),
age: yup.number().required(),
});
type FormValues = InferType<typeof schema>;
const form = useForm<FormValues>({
resolver: yupResolver(schema),
});
Это создаёт синхронизацию между схемой и формой, исключая рассинхронизацию типов и фактической структуры данных.
Resolver всегда получает все значения формы, но ошибки могут быть привязаны только к части полей. Это важно при динамических формах, где поля могут добавляться или удаляться.
const schema = yup.object({
email: yup.string().required(),
});
Если в форме есть дополнительные поля, не описанные в схеме, они:
errors;values, если схема позволяет
noUnknown.Каждый вызов resolver — это полный прогон схемы. При сложных формах это может включать:
Оптимизация достигается за счёт:
abortEarly: false (уже применяется в
yupResolver);После выполнения resolver обновляет formState:
errors — текущие ошибки;isValid — валидность всей формы;isSubmitting — состояние отправки;dirtyFields — изменённые поля.const {
register,
handleSubmit,
formState: { errors, isValid },
} = useForm({
resolver: yupResolver(schema),
});
Важно, что isValid зависит от последнего результата
resolver, а не от локальных проверок отдельных полей.
При вызове reset значения формы сбрасываются, но
resolver не вызывается автоматически. Ошибки также очищаются, если это
не переопределено вручную.
form.reset({
email: "",
password: "",
});
После reset следующая валидация снова будет проходить через resolver как при первом запуске.
В некоторых случаях schema может зависеть от состояния:
const resolver = (values, context, options) => {
return userType === "admin"
? yupResolver(adminSchema)(values, context, options)
: yupResolver(userSchema)(values, context, options);
};
useForm({
resolver,
});
Такой подход позволяет динамически менять правила валидации без изменения структуры формы.
Если Yup содержит асинхронные тесты:
yup.string().test("check-db", async (value) => {
const exists = await api.checkEmail(value);
return !exists;
});
resolver ожидает завершения Promise перед обновлением состояния формы. Это влияет на UX:
Resolver задаёт строгий контракт между:
React Hook Form не интерпретирует правила схемы — он работает только с результатом resolver, что делает систему расширяемой и независимой от конкретной библиотеки валидации.