Работа с массивами объектов в схемах валидации требует точного описания структуры каждого элемента, поскольку ошибка может возникать на уровне как массива в целом, так и отдельного поля внутри вложенного объекта. В контексте React Hook Form и интеграции с Yup особое значение приобретает механизм резолвера, реализуемый через YupResolver, который преобразует результаты проверки схемы в формат, совместимый с формой.
Базовый подход к описанию массива объектов строится вокруг комбинации
array() и object():
Типовая схема принимает следующий вид:
import * as Yup from "yup";
const schema = Yup.object({
users: Yup.array()
.of(
Yup.object({
id: Yup.number().required(),
name: Yup.string().required(),
email: Yup.string().email().required()
})
)
});
Каждый элемент массива становится независимой сущностью валидации, но
при этом сохраняет связь с родительским полем users.
При работе с массивами объектов формируется иерархическая структура ошибок:
users — ошибка уровня массиваusers[0] — ошибка конкретного элементаusers[0].email — ошибка конкретного поля объектаТакой формат позволяет точно локализовать проблему, однако требует корректного преобразования в UI-слое, поскольку плоская модель ошибок не отражает вложенность.
Пример результата ошибки:
{
users: [
null,
{ email: "Некорректный email" },
null
]
}
или в формате path-based структуры:
{
"users[1].email": "Некорректный email"
}
Разные реализации резолверов могут возвращать различные форматы, но YupResolver приводит их к форме, совместимой с React Hook Form.
Массивы объектов часто применяются в динамических формах, где количество элементов изменяется во время выполнения. Типичный сценарий — список пользователей, товаров, адресов.
const defaultValues = {
users: [
{ id: 1, name: "", email: "" }
]
};
При использовании useFieldArray структура
синхронизируется с Yup-схемой:
Ключевая особенность заключается в том, что индексация массива становится частью пути ошибки, что влияет на отображение сообщений.
Массивы объектов часто содержат дополнительные уровни вложенности. Например:
const schema = Yup.object({
orders: Yup.array().of(
Yup.object({
id: Yup.number().required(),
items: Yup.array().of(
Yup.object({
productId: Yup.number().required(),
quantity: Yup.number().min(1).required()
})
)
})
)
});
Здесь формируется трёхуровневая структура:
Каждый уровень требует отдельной обработки ошибок, особенно при отображении UI, где необходимо сопоставлять индексы с динамическими компонентами.
Пустой массив в Yup по умолчанию считается валидным, если явно не задано ограничение:
Yup.array().min(1, "Должен быть хотя бы один элемент")
Дополнительные ограничения:
min(n) — минимальное количество элементовmax(n) — максимальное количество элементовrequired() — обязательное наличие массиваПри отсутствии этих правил массив может проходить валидацию даже без элементов, что часто становится источником логических ошибок в формах.
Массивы объектов часто требуют нормализации перед проверкой:
Yup поддерживает трансформации:
Yup.array().transform((value) => value.filter(Boolean))
Такие преобразования влияют на итоговую структуру данных до применения схемы объекта.
При интеграции с React Hook Form схема Yup не используется напрямую. Вместо этого применяется резолвер, который:
В случае массивов объектов критически важно, чтобы пути ошибок сохраняли индексную структуру, иначе UI не сможет корректно сопоставить ошибку с конкретным полем.
При больших массивах объектов возникают проблемы производительности:
Практика оптимизации включает:
validateAt для точечной проверкиОсобенно важно избегать пересоздания схемы внутри компонента, поскольку это приводит к полной переоценке массива.
Элементы массива часто зависят друг от друга. Yup поддерживает
условные правила через when:
Yup.object({
type: Yup.string(),
value: Yup.string().when("type", {
is: "email",
then: (schema) => schema.email(),
otherwise: (schema) => schema.min(3)
})
});
В массиве такие условия применяются к каждому объекту независимо, что позволяет реализовать разнородные структуры внутри одного списка.
Результаты валидации массивов объектов часто требуют дополнительной обработки:
Типичный формат нормализации:
{
0: { email: "Ошибка" },
2: { name: "Обязательное поле" }
}
Такой подход упрощает отображение ошибок в компонентах, работающих с индексами массива.
При изменении массива важно учитывать стратегию повторной валидации:
YupResolver обеспечивает согласованность между структурой Yup и
состоянием формы, но логика частичной валидации зависит от конфигурации
формы и используемого режима проверки (mode,
reValidateMode).
Массивы объектов требуют строгого соответствия между
defaultValues и схемой:
undefinedКорректная инициализация снижает количество ошибок синхронизации между UI и схемой.
При использовании TypeScript массивы объектов становятся источником сложных типов:
Array<InferType<typeof schema>>Это позволяет предотвратить ошибки ещё до этапа выполнения, особенно при динамическом добавлении элементов.
Массивы объектов часто комбинируются с:
Пример сложной структуры:
Yup.object({
project: Yup.string(),
teams: Yup.array().of(
Yup.object({
name: Yup.string(),
members: Yup.array().of(
Yup.object({
username: Yup.string(),
role: Yup.string()
})
)
})
)
});
Такие схемы требуют строгого контроля путей ошибок и внимательной синхронизации индексов.
Асинхронные проверки (например, проверка уникальности email) внутри массивов выполняются для каждого элемента независимо:
При этом резолвер агрегирует результаты в единый объект ошибок, сохраняя структуру массива.
При удалении элементов массива индексы пересчитываются, что влияет на:
Корректная обработка требует пересчёта путей всех последующих элементов, иначе возможны «смещённые» ошибки.
Массив объектов допускает частичное заполнение до момента финальной валидации:
undefinedЭто поведение особенно важно при пошаговом заполнении форм, где элементы массива создаются постепенно.