Yup по умолчанию ориентирован на валидацию целой схемы данных. Это
означает, что вызов schema.validate(values) запускает
проверку всех полей, даже если изменилось только одно значение. В
реальных формах такой подход часто становится избыточным: пользователь
редактирует одно поле, но получает ошибки сразу по всей форме, включая
незатронутые значения.
В задачах интерфейсной валидации возникает необходимость ограничить проверку только изменёнными или затронутыми полями. Это снижает количество вычислений, уменьшает «шум» ошибок и делает поведение формы более предсказуемым.
Механизм validateAt(path, value) позволяет проверять
конкретное поле по пути в объекте данных.
import * as Yup from "yup";
const schema = Yup.object({
email: Yup.string().email().required(),
password: Yup.string().min(8).required(),
});
schema.validateAt("email", {
email: "test@example.com",
password: ""
});
Особенности подхода:
email)Этот метод особенно полезен при обработке событий
onChange или onBlur, когда изменяется только
одно поле.
В связке с форм-библиотеками, такими как Formik, часто используется
механизм отслеживания изменённых полей (dirty и
touched).
Formik предоставляет структуру состояния:
dirty — были ли изменения в формеtouched — какие поля были затронуты пользователемПример выборочной валидации:
const validateChangedFields = async (values, touched) => {
const changedFields = Object.keys(touched);
const errors = {};
for (const field of changedFields) {
try {
await schema.validateAt(field, values);
} catch (err) {
errors[field] = err.message;
}
}
return errors;
};
Такой подход позволяет:
В React Hook Form концепция dirty-логики встроена на уровне
библиотеки. Она предоставляет объект formState.dirtyFields,
содержащий только изменённые поля.
Пример использования с Yup:
import { useForm } from "react-hook-form";
import * as Yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
const schema = Yup.object({
username: Yup.string().required(),
age: Yup.number().required(),
});
const { register, handleSubmit, formState } = useForm({
resolver: yupResolver(schema),
});
Для частичной валидации можно использовать
dirtyFields:
const onSub mit = async (data) => {
const changed = Object.keys(formState.dirtyFields);
for (const field of changed) {
await schema.validateAt(field, data);
}
};
Такой подход особенно эффективен в формах с большим количеством полей, где полная валидация на каждом изменении становится дорогой операцией.
Yup позволяет создавать подмножества схем, что удобно для изолированной валидации.
const partialSchema = schema.pick(["email"]);
await partialSchema.validate({ email: "test@example.com" });
Используется, когда набор изменяемых полей известен заранее.
const emailSchema = Yup.reach(schema, "email");
await emailSchema.validate("test@example.com");
Подходит для динамического доступа к вложенным полям.
При работе со сложными структурами данных частичная валидация становится более тонкой задачей.
const schema = Yup.object({
user: Yup.object({
profile: Yup.object({
name: Yup.string().required(),
age: Yup.number().required(),
})
})
});
Валидация конкретного поля:
await schema.validateAt("user.profile.name", values);
Это позволяет:
userНесмотря на удобство, частичная проверка имеет ряд особенностей:
confirmPassword зависит от password)when) могут требовать контекста всей
формыtransform) могут давать разные
результаты при неполной проверкеПример зависимости:
confirmPassword: Yup.string().oneOf([Yup.ref("password")])
При валидации только confirmPassword без
password возможны некорректные результаты.
Наиболее стабильный подход строится на объединении нескольких механизмов:
dirtyFields или
touched)validateAtconst validateDirtyOnly = async (values, dirtyFields) => {
const errors = {};
for (const key of Object.keys(dirtyFields)) {
try {
await schema.validateAt(key, values);
} catch (e) {
errors[key] = e.message;
}
}
return errors;
};
Такой подход даёт предсказуемую модель обновления ошибок без полной переработки всей схемы на каждом шаге ввода.
Параметр abortEarly: false влияет только на сбор ошибок
внутри одного поля или всей схемы, но не решает задачу ограничения
области проверки.
await schema.validate(values, { abortEarly: false });
При частичной валидации через validateAt он практически
не играет роли, так как проверяется один путь, а не вся структура.
Частичная валидация становится критичной в следующих случаях:
В таких сценариях переход от полной проверки к точечной снижает нагрузку и делает UX более стабильным за счёт отсутствия «перепроверки всего» при каждом изменении одного значения.