본문 바로가기
카테고리 없음

[React] React Hook Form과 Zod로 폼 유효성 검증 구현

by yuraming 2026. 3. 12.

 

단순한 데이터 검증을 넘어, 사용자 입력을 관리할 때.

React Hook FormZod를 함께 사용하면 코드의 양은 크게 줄어들고, 타입 안정성은 극대화될 수 있습니다..

 

1. 시작, 필수 패키지 설치

 

React Hook Form과 Zod를 연결해주는 어댑터인 @hookform/resolvers 추가로 설치.

npm install react-hook-form zod @hookform/resolvers

 

 

 

2. 왜 이 조합?

기본적인 React Hook Form의 register 방식은 검증 로직이 JSX 안에 파편화되어 유지보수가 어려움.

하지만 Zod를 연동하면 하기의 장점이 있습니다.

  • 비즈니스 로직의 분리: 검증 로직(Schema)을 컴포넌트 외부에서 관리할 수 있다.
  • 강력한 타입 추론: 폼에 입력된 데이터의 타입을 별도로 정의할 필요가 없다.
  • 일관된 에러 메시지: 복잡한 조건부 렌더링 없이 Zod 스키마에 정의된 에러 메시지를 그대로 출력할 수 있다.

 

 

3. 실전 예제: 회원가입 폼 구현

가장 전형적인 회원가입 시나리오를 통해 연동 방법을 살펴보겠습니다.

① 스키마 정의하기

먼저 폼의 구조와 검증 규칙을 정의.

import { z } from "zod";

export const signupSchema = z.object({
  email: z.string().email("유효한 이메일을 입력해주세요."),
  password: z
    .string()
    .min(8, "비밀번호는 최소 8자 이상이어야 합니다.")
    .regex(/[A-Z]/, "최소 하나의 대문자가 포함되어야 합니다."),
  confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
  path: ["confirmPassword"],
  message: "비밀번호가 일치하지 않습니다.",
});

// 스키마를 통해 타입 추출
export type SignupInput = z.infer<typeof signupSchema>;

 

 

② 컴포넌트에 적용하기

useForm의 resolver 옵션에 zodResolver를 넘겨줌.

import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

const SignupForm = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<SignupInput>({
    resolver: zodResolver(signupSchema), // Zod 연동
    mode: "onChange", // 실시간 검증 활성화
  });

  const onSubmit = (data: SignupInput) => {
    console.log("제출된 데이터:", data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <input {...register("email")} placeholder="이메일" />
        {errors.email && <p>{errors.email.message}</p>}
      </div>

      <div>
        <input type="password" {...register("password")} placeholder="비밀번호" />
        {errors.password && <p>{errors.password.message}</p>}
      </div>

      <div>
        <input type="password" {...register("confirmPassword")} placeholder="비밀번호 확인" />
        {errors.confirmPassword && <p>{errors.confirmPassword.message}</p>}
      </div>

      <button type="submit">회원가입</button>
    </form>
  );
};

 

 

 

 

4. 요약

  • zodResolver: React Hook Form이 유효성 검사를 할 때 Zod 스키마를 사용하도록 징검다리 역할.
  • errors 객체: Zod 스키마에서 정의한 message가 자동으로 errors.[field].message에 매핑.
  • Type Safety: useForm<SignupInput>처럼 제네릭을 넘겨주면, register 함수를 사용할 때 오타를 내거나 잘못된 필드명을 입력하는 것을 방지해줌.

 

 

 


마치며

React Hook Form과 Zod의 조합은 이제 현대적인 React 개발에서 표준에 가깝게 자리 잡았고.

폼이 복잡해질수록 이 조합이 주는 생산성은 더욱 커집니다. 단순히 값을 검사하는 것을 넘어, 서버로 보내기 전 데이터의 '최종 검증'에 최적의 조합입니다.