Механизм ссылок на другие поля в схемах валидации позволяет строить
зависимые правила, где значение одного поля участвует в проверке
другого. В экосистеме Yup это реализуется через Yup.ref,
который формирует «указатель» на значение поля внутри текущего объекта
схемы. В связке с YupResolver этот подход становится ключевым
инструментом для построения согласованных форм с перекрёстной
валидацией.
Yup.ref не извлекает значение напрямую в момент
объявления схемы. Он создаёт абстрактную ссылку, которая разрешается во
время выполнения валидации.
Суть механизма:
ref указывает, какое поле использовать как источник
значенияБазовая форма использования:
Yup.ref('fieldName')
Такой вызов означает: «возьми значение поля fieldName из
текущего объекта данных».
Наиболее частый сценарий — сравнение значений двух полей. Это используется в подтверждении пароля, проверке диапазонов дат, ограничениях чисел.
Пример сравнения строк:
import * as Yup from 'yup';
const schema = Yup.object({
password: Yup.string().required(),
confirmPassword: Yup.string()
.oneOf([Yup.ref('password')], 'Пароли не совпадают')
});
Здесь confirmPassword зависит от значения
password. YupResolver передаёт объект формы целиком, и Yup
проверяет соответствие в момент валидации.
Ссылки работают не только со строками, но и с числами:
const schema = Yup.object({
min: Yup.number().required(),
max: Yup.number()
.min(Yup.ref('min'), 'Максимум должен быть больше минимума')
});
Такая схема гарантирует логическую согласованность диапазона.
Валидация происходит динамически, поэтому изменение min
сразу влияет на поведение max.
Один из наиболее практичных сценариев — контроль дат.
const schema = Yup.object({
startDate: Yup.date().required(),
endDate: Yup.date()
.min(Yup.ref('startDate'), 'Дата окончания не может быть раньше начала')
});
В контексте YupResolver это особенно важно, поскольку формы часто обновляются интерактивно, и зависимые поля должны реагировать мгновенно.
Сложные формы часто содержат структуры:
const schema = Yup.object({
items: Yup.array().of(
Yup.object({
price: Yup.number().required(),
discountPrice: Yup.number()
.max(Yup.ref('price'), 'Скидка не может превышать цену')
})
)
});
Здесь ref работает в локальном контексте объекта
массива. Это означает, что ссылка всегда относится к полям текущего
элемента, а не к внешней структуре.
При использовании YupResolver важно учитывать, что каждый элемент массива валидируется независимо, но с доступом к соседним полям внутри объекта.
YupResolver передаёт данные формы в Yup как единый объект. В момент валидации:
ref разрешается относительно текущего уровня
объектаЭто означает, что Yup.ref не является реактивной ссылкой
в стиле state management. Это вычисляемое значение, актуальное на момент
вызова validate.
Одно из наиболее мощных применений — условная валидация через
when.
const schema = Yup.object({
isCompany: Yup.boolean(),
companyName: Yup.string().when('isCompany', {
is: true,
then: (schema) => schema.required('Укажите название компании'),
otherwise: (schema) => schema.notRequired()
})
});
Здесь when использует внутренний механизм ссылок,
аналогичный ref. Более явная форма:
Yup.string().when(Yup.ref('isCompany'), {
is: true,
then: (schema) => schema.required()
});
В YupResolver такие зависимости позволяют строить динамические формы без ручного пересчёта состояния.
Несмотря на гибкость, механизм ссылок имеет ряд особенностей:
ref не отслеживает изменения в реальном времени вне
валидацииundefined могут влиять на сравнениеtransform) выполняются до разрешения
ссылкиПример потенциальной проблемы:
Yup.number().min(Yup.ref('minValue'))
Если minValue отсутствует, результат сравнения может
стать неожиданным. В таких случаях требуется явная обработка:
Yup.number().when('minValue', (minValue, schema) =>
minValue !== undefined
? schema.min(minValue)
: schema
)
При использовании YupResolver в связке с формами (например, React Hook Form) важно учитывать порядок инициализации:
Это означает, что если поле не задано в defaultValues,
ref может ссылаться на undefined, что изменяет
поведение условий.
На практике Yup.ref чаще всего используется в следующих
случаях:
Подтверждение значений:
Yup.string().oneOf([Yup.ref('email')])
Диапазоны:
Yup.number().max(Yup.ref('budget'))
Зависимые поля:
Yup.string().when('mode', (mode, schema) =>
mode === 'advanced' ? schema.required() : schema
)
Кросс-валидация объектов:
Yup.object({
from: Yup.date(),
to: Yup.date().min(Yup.ref('from'))
})
Когда схема содержит ref, YupResolver обрабатывает
ошибки так же, как и обычные проверки:
min,
oneOf, required)Например, если confirmPassword не совпадает с
password, ошибка будет принадлежать только
confirmPassword.
Yup поддерживает доступ к вложенным полям через строковый путь:
Yup.ref('user.password')
Это особенно полезно для структурированных объектов:
const schema = Yup.object({
user: Yup.object({
password: Yup.string(),
confirm: Yup.string().oneOf([Yup.ref('user.password')])
})
});
Такая форма позволяет строить сложные модели данных без необходимости расплющивания структуры.
Если поле содержит transform, порядок выполнения
становится критичным:
Yup.number()
.transform((value) => Number(value))
.min(Yup.ref('minValue'))
Сначала выполняется преобразование, затем разрешение ссылки. Это может приводить к различию между исходным строковым вводом и числовым сравнением.
Yup.ref может использоваться внутри
.test():
Yup.string().test(
'match-check',
'Значения не совпадают',
function (value) {
return value === this.resolve(Yup.ref('otherField'))
}
)
Здесь this.resolve — внутренний механизм Yup, который
разворачивает ссылку в актуальное значение.
В крупных формах с множеством зависимостей ref
становится инструментом связывания логики:
Однако чрезмерное использование перекрёстных ссылок усложняет поддержку схемы. Особенно это заметно при глубокой вложенности и множественных уровнях зависимостей, где изменение одного поля может влиять на цепочку проверок.
Если имя поля формируется динамически, ref может стать
менее предсказуемым:
Yup.ref(`fields.${index}.value`)
В таких случаях важно контролировать стабильность структуры данных, поскольку изменение индексов или ключей приведёт к изменению логики валидации.
Если целевое поле отсутствует, Yup применяет стандартные правила сравнения:
undefined считается отсутствующим значениемfalseoneOf, equals) могут
вести себя по-разному в зависимости от типа данныхЭто требует явного контроля обязательности полей при проектировании схем.
Механизм ссылок превращает схему Yup в граф зависимостей между полями. В сочетании с YupResolver это позволяет:
При этом вся логика остаётся синхронной и детерминированной, что упрощает отладку и тестирование форм.