
React Hook Form이란?
React Hook Form은 React에서 폼(Form)의 상태와 검증을 효율적으로 관리하기 위한 라이브러리이다.
회원가입, 로그인, 검색, 결제 정보 입력처럼 사용자의 입력을 받는 화면에서는 보통 다음과 같은 작업이 필요하다.
- 입력값 관리
- 입력값 검증
- 에러 메시지 표시
- 제출 처리
- 폼 상태 관리
React 기본 기능만 사용하면 이러한 코드를 직접 작성해야 한다.
입력값마다 상태를 만들고 변경 이벤트를 처리해야 하기 때문에 폼이 복잡해질수록 코드가 증가한다.
React Hook Form은 이러한 반복적인 폼 관리 로직을 줄여주는 라이브러리이다.
React Hook Form 은 어떻게 폼 관리를 해줄까?
1. React 상태 관리 코드 감소
일반적인 React 방식에서는 입력값마다 useState를 사용한다.
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
입력 필드가 많아질수록 상태와 이벤트 핸들러가 계속 증가한다.
React Hook Form을 사용하면 아래와 같이 입력값 등록을 한다.
<input {...register("email")} />
<input {...register("password")} />
2. 불필요한 리렌더링 감소
React에서 입력값을 useState로 관리하면 값이 변경될 때마다 컴포넌트가 다시 렌더링된다.
입력
↓
state 변경
↓
컴포넌트 리렌더링
React Hook Form은 기본적으로 Uncontrolled Component 방식을 사용한다.
즉, 입력값을 useState에 저장하며 관리하는 것이 아니라 DOM이 직접 값을 관리하고, 필요한 시점에만 React Hook Form이 해당 값을 읽어온다.
사용자 입력
↓
DOM에서 값 관리
↓
필요할 때만 React에 전달
이를 통해 많은 입력 필드를 가진 폼에서도 성능상 이점을 얻을 수 있다.
React Hook Form 기본 사용법
1. useForm 생성
import { useForm } from "react-hook-form";
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
각 기능의 역할:
| register | input 등록 |
| handleSubmit | 제출 처리 |
| errors | 검증 오류 관리 |
2. input 등록
<input {...register("email")}/>
register는 input 요소를 React Hook Form에 등록하여 입력값을 추적하고 관리할 수 있도록 한다.
내부적으로:
- 입력값 추적
- 변경 감지
- 제출 데이터 수집
을 처리한다.
3. 데이터 제출
const onSubmit = (data) => {
console.log(data);
};
<form onSubmit={handleSubmit(onSubmit)}>
<button>
제출
</button>
</form>
4. 입력값 검증
React Hook Form은 required, minLength, pattern 등 기본적인 입력값 검증도 지원한다.
<input {...register("email", { required: "이메일을 입력해주세요.",})}/>
입력하지 않으면 메시지를 보여줄 수 있다.
옵션
| required | 필수 입력 여부 | required: "이메일을 입력해주세요." |
| minLength | 최소 글자 수 | minLength: { value: 8, message: "8자 이상 입력해주세요." } |
| maxLength | 최대 글자 수 | maxLength: { value: 20, message: "20자 이하로 입력해주세요." } |
| min | 최소 숫자 값 | min: { value: 1, message: "1 이상 입력해주세요." } |
| max | 최대 숫자 값 | max: { value: 100, message: "100 이하만 가능합니다." } |
| pattern | 정규식을 이용한 형식 검증 | pattern: { value: /^[A-Za-z]+$/, message: "영문만 입력 가능합니다." } |
| validate | 직접 검증 함수 작성 | `validate: (value) => value !== "admin" |
5. Zod와 함께 사용하기
React Hook Form은 입력값과 폼 상태를 관리하고,
Zod는 입력된 데이터가 올바른 형식인지 검증한다.
두 라이브러리를 함께 사용하면 입력 관리와 검증을 깔끔하게 분리할 수 있어 실무에서도 많이 사용된다.
로그인 화면 구현 예시
"use client";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
/**
* 1. Zod 스키마 정의
*/
const LoginSchema = z.object({
email: z
.string()
.min(1, "이메일을 입력해주세요.")
.email("올바른 이메일 형식이 아닙니다."),
password: z
.string()
.min(8, "비밀번호는 8자 이상 입력해주세요."),
});
/**
* 2. TypeScript 타입 생성
*/
type LoginFormData = z.infer<typeof LoginSchema>;
export default function LoginPage() {
/**
* 3. React Hook Form 설정
* register
* -> input과 연결하는 함수
* handleSubmit
* -> 제출 시 실행할 함수 관리
* errors
* -> Zod 검증 실패 메시지 저장
*/
const {
register,
handleSubmit,
formState: {errors,isSubmitting,},
} = useForm<LoginFormData>({
/**
* React Hook Form과 Zod 연결
*
* submit 전에 LoginSchema로 검증한다.
*/
resolver: zodResolver(LoginSchema),
});
/**
* 4. 로그인 제출 함수
*/
const onSubmit = async (
data: LoginFormData
) => {
try {
const response =
await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json",},
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error("로그인 실패");
}
alert("로그인 성공");
} catch(error) {
alert(
"이메일 또는 비밀번호를 확인해주세요."
);
}
};
return (
<div>
<h1>로그인</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<input
type="email"
placeholder="이메일"
/**
* register를 통해
* React Hook Form에 등록
*/
{...register("email")}
/>
{errors.email && (<p> {errors.email.message} </p>)}
</div>
<div>
<input
type="password"
placeholder="비밀번호"
{...register("password")}
/>
{errors.password && (<p>{errors.password.message}</p>)}
</div>
<button type="submit" disabled={isSubmitting}>
{isSubmitting? "로그인 중...": "로그인"}
</button>
</form>
</div>
);
}
'Library' 카테고리의 다른 글
| Zustand (0) | 2026.06.22 |
|---|---|
| TypeScript를 쓰는데 왜 Zod까지 사용할까? (0) | 2026.06.18 |
| TanStack Query란? (서버상태 관리도구) (0) | 2026.06.17 |