TanStack Router предоставляет гибкую систему маршрутизации для React и других JavaScript-фреймворков. Одной из ключевых задач при работе с маршрутизатором является валидация параметров маршрута и данных запроса. Для этого удобно использовать библиотеку Zod, которая позволяет создавать строгие схемы валидации и безопасно типизировать данные.
Zod работает на основе декларативных схем. Каждая схема описывает структуру данных и условия, которым они должны соответствовать:
import { z } from "zod";
const userSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1),
age: z.number().int().positive()
});
В этом примере схема userSchema проверяет объект с тремя
полями: id должен быть UUID, name — непустая
строка, age — положительное целое число.
TanStack Router позволяет определять маршруты с параметрами. С помощью Zod можно валидировать эти параметры до передачи их компоненту:
import { createRouter, createRoute } from "@tanstack/router";
const userRoute = createRoute({
path: "/user/:id",
validate: ({ params }) => {
const result = z.object({ id: z.string().uuid() }).safeParse(params);
if (!result.success) {
throw new Error("Неверный параметр маршрута");
}
return result.data;
},
component: UserPage
});
const router = createRouter({
routes: [userRoute]
});
Здесь validate используется для проверки параметров
маршрута перед тем, как компонент UserPage получит доступ к
данным.
В TanStack Router также можно валидировать query-параметры. Например, для фильтров или пагинации:
const searchRoute = createRoute({
path: "/search",
validate: ({ query }) => {
return z.object({
q: z.string().min(3),
page: z.string().regex(/^\d+$/).transform(Number).default(1)
}).parse(query);
},
component: SearchPage
});
q — поисковая строка, минимум 3 символа.page — номер страницы, преобразуется из строки в число
с дефолтным значением 1.Zod хорошо работает не только с маршрутизатором, но и с формами. В связке с TanStack Router это позволяет безопасно передавать данные между страницами и компонентами:
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
const formSchema = z.object({
email: z.string().email(),
password: z.string().min(6)
});
function LoginForm() {
const { register, handleSubmit, formState } = useForm({
resolver: zodResolver(formSchema)
});
const onSub mit = data => {
router.navigate({ to: "/dashboard", params: { userId: data.email } });
};
return (
);
}
Использование zodResolver обеспечивает строгую проверку
данных формы перед навигацией, предотвращая ошибки на уровне
маршрутизации.
Zod поддерживает асинхронные схемы, что удобно для проверки данных на сервере:
const userIdSchema = z.string().uuid().refine(async (id) => {
const response = await fetch(`/api/users/${id}`);
const exists = await response.json();
return exists;
}, {
message: "Пользователь не найден"
});
const userRoute = createRoute({
path: "/user/:id",
validate: async ({ params }) => {
return await userIdSchema.parseAsync(params.id);
},
component: UserPage
});
Асинхронная валидация позволяет проверять параметры маршрута на сервере, прежде чем рендерить компонент, что повышает безопасность приложения.
Zод позволяет автоматически выводить типы TypeScript из схем, что интегрируется с TanStack Router:
type User = z.infer;
const fetchUser = async (id: string): Promise => {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
return userSchema.parse(data);
};
Это обеспечивает согласованность типов на всем протяжении приложения, от API до компонентов и маршрутов.
Для сложных приложений можно создавать вложенные маршруты с отдельными схемами валидации:
const postsRoute = createRoute({
path: "/users/:userId/posts/:postId",
validate: ({ params }) => z.object({
userId: z.string().uuid(),
postId: z.string().uuid()
}).parse(params),
component: PostPage
});
Каждый уровень маршрута может иметь собственную схему Zod, что позволяет управлять валидацией независимо и избежать дублирования кода.