Mục lục

Xóa bỏ if/else Validation: Làm chủ Zod Schema

Tại sao nên dùng Zod thay vì tự viết logic validate? Cách kết hợp Zod với React Hook Form. Chia sẻ Schema giữa Frontend và Backend.

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:

  1. Chainable: .string().min().max().email(). Đọc như văn xuôi.
  2. 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.

  1. File schemas.ts: Chứa SignUpSchema.
  2. Client (page.tsx): Dùng để hiện lỗi UX ngay khi user gõ sai.
  3. Server (actions.ts hoặ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.

Quảng cáo
mdhorizontal