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 |