Validation là cơn ác mộng: Kiểm tra rỗng, kiểm tra email, check pass trùng nhau, check độ dài...
Nếu bạn viết bằng if/else, code sẽ dài như sớ táo quân.
1. Zod - Schema Definition
Zod cho phép bạn khai báo "Hình dáng" của dữ liệu.
ts:
import { z } from "zod";
const SignUpSchema = z.object({
username: z.string().min(3, "Tên ngắn quá (tối thiểu 3 ký tự)"),
email: z.string().email("Email không hợp lệ"),
age: z.number().min(18, "Chưa đủ 18 tuổi"),
password: z.string().min(8),
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
message: "Mật khẩu không khớp",
path: ["confirmPassword"], // Chỉ định lỗi hiện ở trường này
});Sức mạnh của Zod:
- Chainable:
.string().min().max().email(). Đọc như văn xuôi. - TypeScript Free: Tự động tạo type TS.
ts:
type SignUpType = z.infer<typeof SignUpSchema>; // Tự động có: { username: string; email: string; ... }
2. Kết nối với React Hook Form
Dùng zodResolver để RHF hiểu được Zod.
tsx:
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
export function SignUpForm() {
const {
register,
handleSubmit,
formState: { errors } // Lấy lỗi ra
} = useForm<SignUpType>({
resolver: zodResolver(SignUpSchema), // 🔌 Cắm vào đây
});
const onSubmit = (data) => console.log("Valid data:", data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("email")} />
{/* Hiện lỗi màu đỏ */}
{errors.email && <p className="text-red-500">{errors.email.message}</p>}
<button>Submit</button>
</form>
);
}3. "Isomorphic Validation" (Client & Server)
Đây là điểm ăn tiền nhất của Zod. Bạn có thể dùng CÙNG MỘT SCHEMA cho cả 2 đầu.
- File
schemas.ts: ChứaSignUpSchema. - Client (
page.tsx): Dùng để hiện lỗi UX ngay khi user gõ sai. - Server (
actions.tshoặc API): Dùng để parse data lần cuối (chống hacker bypass client).
ts:
// app/actions.ts
'use server';
import { SignUpSchema } from '@/lib/schemas';
export async function registerUser(formData: unknown) {
// Parse an toàn: Trả về success true/false chứ không throw error
const result = SignUpSchema.safeParse(formData);
if (!result.success) {
return { errors: result.error.flatten().fieldErrors };
}
// Save to DB...
}Kết luận
Với bộ đôi React Hook Form (Quản lý State) + Zod (Quản lý Validation), bạn có trong tay vũ khí mạnh nhất để xử lý Form. Code ngắn, sạch, và Type-safe tuyệt đối.