Валидация форм в React строится вокруг управления состоянием полей, обработки пользовательского ввода и проверки данных до их отправки на сервер. При усложнении логики форм ручная проверка быстро становится громоздкой: появляются дублирующиеся условия, разрозненные проверки и сложность синхронизации типов данных между фронтендом и API. Использование схем валидации позволяет централизовать правила и обеспечить предсказуемость структуры данных.
Библиотека Zod предоставляет декларативный подход к описанию схем данных с полной поддержкой TypeScript. Основная идея заключается в том, что структура данных описывается один раз и затем используется как для проверки значений, так и для вывода типов.
В основе Zod лежат схемы, описывающие ожидаемую структуру объекта. Каждое поле получает набор ограничений, которые проверяются во время выполнения.
import { z } from "zod";
const userSchema = z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
age: z.number().int().positive()
});
Схема определяет контракт данных. При попытке валидации входящего объекта происходит проверка всех полей:
const result = userSchema.safeParse({
name: "Alex",
email: "alex@mail.com",
age: 25
});
Метод safeParse возвращает объект с результатом, не
выбрасывая исключений. Это важно для React-приложений, где ошибки
валидации должны управляться через состояние интерфейса.
В React формы обычно управляются через локальное состояние или специализированные библиотеки. В связке с Zod часто используется React вместе с контроллерами форм, такими как react-hook-form.
Схема становится источником истины, а React-компонент отвечает только за отображение состояния.
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
const form = useForm({
resolver: zodResolver(userSchema)
});
В этом подходе валидация отделяется от UI-логики. React получает уже проверенные данные или список ошибок, привязанных к конкретным полям.
Результат валидации Zod структурирован. Ошибки можно сопоставить с конкретными полями формы:
const { errors } = form.formState;
console.log(errors.name?.message);
Каждое поле содержит сообщение об ошибке, сформированное на основе правил схемы. Это позволяет унифицировать обработку ошибок без ручного написания условий в компонентах.
Одним из ключевых преимуществ Zod является интеграция с TypeScript. Типы выводятся автоматически из схемы:
type User = z.infer<typeof userSchema>;
Это устраняет дублирование типов между фронтендом и схемой валидации. Любое изменение схемы автоматически отражается в типах данных.
В контексте форм это означает, что значения формы и валидированные данные всегда синхронизированы по структуре.
Помимо стандартных методов проверки, Zod поддерживает
пользовательские условия через refine:
const passwordSchema = z.string().min(8).refine((val) => {
return /[A-Z]/.test(val) && /[0-9]/.test(val);
}, {
message: "Пароль должен содержать заглавную букву и цифру"
});
Такой подход позволяет реализовывать бизнес-логику, не выходя за пределы схемы.
В React это особенно важно, поскольку логика проверки становится частью декларативного описания данных, а не компонента.
Схемы могут быть композиционными. Это позволяет строить сложные формы из повторно используемых блоков:
const addressSchema = z.object({
city: z.string(),
street: z.string(),
zip: z.string()
});
const userSchema = z.object({
name: z.string(),
address: addressSchema
});
Такая структура снижает дублирование и упрощает поддержку больших форм, где одни и те же блоки используются в разных контекстах.
Сложные формы часто требуют динамических правил. Zod поддерживает
условную логику через superRefine:
const schema = z.object({
password: z.string(),
confirmPassword: z.string()
}).superRefine((data, ctx) => {
if (data.password !== data.confirmPassword) {
ctx.addIssue({
path: ["confirmPassword"],
message: "Пароли не совпадают",
code: "custom"
});
}
});
Это позволяет описывать зависимости между полями без нарушения структуры схемы.
Некоторые проверки требуют обращения к серверу, например проверка уникальности email. Zod поддерживает асинхронные схемы:
const emailSchema = z.string().email().refine(async (email) => {
const res = await fetch(`/api/check-email?email=${email}`);
const data = await res.json();
return data.available;
}, {
message: "Email уже используется"
});
В React такие проверки обычно комбинируются с debounce, чтобы снизить нагрузку на сервер и не выполнять запрос при каждом изменении поля.
Формы часто содержат списки элементов, например набор телефонов или адресов. Zod предоставляет инструменты для работы с массивами:
const schema = z.object({
phones: z.array(z.string().min(10))
});
В React это используется для динамического добавления и удаления полей без изменения общей структуры формы.
Zod позволяет трансформировать данные в процессе валидации:
const schema = z.object({
age: z.string().transform((val) => Number(val))
});
Это особенно полезно при работе с HTML-формами, где все значения приходят в виде строк.
Формы часто содержат поля, которые могут отсутствовать. Zod явно поддерживает такие случаи:
const schema = z.object({
middleName: z.string().optional()
});
Отсутствие значения не приводит к ошибке, что упрощает обработку частично заполненных форм.
В React-архитектуре валидация через Zod часто связывается с состояниями интерфейса: loading, error, success. Схема выступает источником правил, а UI реагирует на результат проверки.
Ошибки могут отображаться сразу после изменения поля или только при отправке формы. Поведение определяется уровнем интеграции с менеджером формы.
Использование схем валидации переносит часть бизнес-логики из компонентов в отдельный слой. Это снижает связность и делает код предсказуемым при масштабировании.
Схема становится универсальным контрактом между интерфейсом, сервером и типами данных.