STUDY/[ React ]

Zod 라이브러리와 React-Hook-Form

Lim임 2026. 1. 7. 17:34

Zod에서 React Hook Form

1. 처음 질문 — Zod는 왜 쓰는 거지?

처음 질문은 단순했다.

TypeScript로 타입을 다 적어두는데, 왜 Zod 같은 라이브러리가 필요하지?

여기서의 전제는 이거였다.

  • TS에 string이라고 적어두면
  • 들어오는 값도 string일 거라고 믿어도 되는 거 아닌가?

하지만 이 전제는 컴파일 타임과 런타임의 차이를 아직 분리하지 못한 상태였다.


2. 첫 번째 오해 — “TS는 null을 몰라서 Zod가 필요한 거야?”

이해 과정에서 이런 생각이 나왔다.

TS는 백엔드에서 오는 데이터가
null인지, "null" 문자열인지 알 수 없어서
Zod로 다시 검증하는 거 아닌가?

여기서 중요한 정정이 필요하다.

  • TS는 모르는 게 아니다
  • TS는 검증을 하지 않는다

즉,

알 수 없어서가 아니라
애초에 런타임 데이터에 관심이 없다

이게 정확한 표현이다.


3. TypeScript의 한계는 명확하다

TypeScript는 다음 시점에만 존재한다.

  • 코드 작성 시점
  • 컴파일 시점
type User = { email: string };

이 코드는 이런 의미다.

"이 코드 안에서 User.email은 string으로 취급하겠다"

하지만 실제 네트워크 응답 데이터는
이 약속을 지켜줄 의무가 없다.

그래서 문제가 생긴다.


4. Zod의 역할 — 런타임 타입 검증

Zod는 이 지점에서 등장한다.

지금 이 데이터가
정말 우리가 기대한 형태인가?

const UserSchema = z.object({
  email: z.string().email(),
});

이건 타입 선언이 아니라 검증 규칙이다.

  • 문자열인지
  • 이메일 형식인지
  • null은 아닌지

실제 값 기준으로 검사한다.

여기까지는 주로 서버에서 오는 데이터를 기준으로 한 이야기다.


5. 자연스럽게 생기는 다음 질문

여기까지 이해하면 이런 생각이 이어진다.

그럼 서버 데이터만 문제일까?

사용자가 입력하는 값도
결국 런타임 데이터 아닌가?

공통점은 분명하다.

  • 서버 응답도
  • 사용자 입력도

모두 코드 바깥에서 들어온 값이다.

즉,

TypeScript가 신뢰할 수 없는 데이터다

여기서 관심사가 자연스럽게
폼 입력값으로 확장된다.


6. React에서 폼을 다루는 가장 기본적인 방식

React에서 가장 정석적인 폼 코드는 보통 이렇게 생겼다.

const [email, setEmail] = useState("");

<input
  value={email}
  onChange={(e) => setEmail(e.target.value)}
/>

이 방식의 특징은 명확하다.

  • 입력값을 state로 관리
  • 값이 바뀔 때마다 setState 호출
  • 그때마다 컴포넌트 리렌더

이 방식 자체가 틀린 건 아니다.


7. 문제가 드러나는 지점

문제는 폼이 커질 때 나타난다.

  • input이 많아질수록 state도 늘어난다
  • 입력할 때마다 리렌더가 발생한다
  • 검증 로직까지 얹으면 코드가 급격히 복잡해진다

여기서 이런 의문이 생긴다.

모든 입력 과정이
정말 React의 리렌더를 필요로 할까?


8. React Hook Form의 출발점

React Hook Form은 이 질문에서 출발한다.

입력 중에는 React가 몰라도 되지 않을까?

핵심 아이디어는 단순하다.

  • 입력 중에는 DOM이 값을 들고 있고
  • React는 제출하거나 검증할 때만 개입한다
const { register, handleSubmit, formState } = useForm();

9. useForm이 하는 실제 역할

  • register
    • input에 이벤트를 직접 연결
    • 값은 DOM에 저장됨
  • handleSubmit
    • submit 시점에 DOM 값 수집
  • formState
    • 에러, 상태만 React가 관리

중요한 점은 이거다.

입력 과정에서는 React state가 거의 바뀌지 않는다

그래서 더 가볍다.


10. 자주 생기는 오해 — 이벤트가 많으면 무겁지 않나?

여기서 이런 질문이 나온다.

onChange 이벤트가 계속 걸려 있으면
오히려 더 무거운 거 아닌가?

답은 명확하다.

  • 브라우저 이벤트는 원래 항상 존재한다
  • 문제의 핵심은 이벤트가 아니라 React 리렌더다

즉,

이벤트는 가볍고
리렌더가 비싸다


11. 그래서 Zod와 React Hook Form이 만나게 된다

정리해보면 역할이 정확히 나뉜다.

  • React Hook Form
    • 런타임 입력값 수집 최적화
  • Zod
    • 수집된 값의 구조와 의미 검증
useForm({
  resolver: zodResolver(schema),
});

이 조합은 우연이 아니다.


12. 전체를 관통하는 한 문장

이 모든 흐름은 하나로 정리된다.

TypeScript는 코드를 믿고
Zod는 데이터를 믿고
React Hook Form은 리렌더를 아낀다

이 글은
"Zod가 왜 필요한가"라는 질문에서 시작해
폼 입력을 다루는 React의 선택까지 이어진
실제 이해 과정이다.

 

'STUDY > [ React ]' 카테고리의 다른 글

React, ReactDOM, Virtual DOM, State 관계 정리  (0) 2026.01.07
목 수업  (0) 2025.12.05
모킹서버 토스트 모달  (0) 2025.12.03
react query  (0) 2025.12.03
도서상세페이지ㅁ(추후)  (0) 2025.11.30