1. 폼 관리의 어려움
리액트로 개발하다 보면 **사용자 입력을 다루는 폼(form)**을 자주 만들게 됩니다.
로그인, 회원가입, 게시글 작성, 검색창 등 거의 모든 페이지에서 사용되죠.
그런데 이런 폼을 useState로 하나씩 관리하기 시작하면 다음과 같은 문제가 생깁니다.
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
입력 필드가 늘어날수록 코드가 복잡해지고,
검증(validation)이나 에러 메시지를 처리하기도 점점 어려워집니다.
이 문제를 해결하기 위해 만들어진 라이브러리가 바로 React Hook Form입니다.
2. React Hook Form이란?
React Hook Form은
“폼을 쉽게, 가볍게, 빠르게 관리할 수 있게 해주는 리액트 훅 기반 라이브러리”
입니다.
특징은 다음과 같습니다.
✅ 비제어 컴포넌트 기반 – 리렌더링을 최소화하여 성능이 뛰어남
✅ 유효성 검사 내장 – 별도 라이브러리 없이도 기본적인 validation 가능
✅ 간단한 API – 코드가 짧고, TypeScript 호환이 우수
3. 설치
npm install react-hook-form
4. 기본 사용법
아래는 React Hook Form의 가장 기본적인 예제입니다.
import React from 'react';
import { useForm } from 'react-hook-form';
function SignupForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>이름</label>
<input {...register('name', { required: '이름은 필수 입력입니다.' })} />
{errors.name && <p style={{ color: 'red' }}>{errors.name.message}</p>}
</div>
<div>
<label>이메일</label>
<input
{...register('email', {
required: '이메일은 필수입니다.',
pattern: {
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
message: '유효한 이메일 형식을 입력해주세요.',
},
})}
/>
{errors.email && <p style={{ color: 'red' }}>{errors.email.message}</p>}
</div>
<button type="submit">회원가입</button>
</form>
);
}
export default SignupForm;
주요 개념
- register() : input을 Hook Form에 등록
- handleSubmit() : 폼 제출 이벤트 핸들러
- errors : 유효성 검사 결과를 담은 객체
✅ useForm() 훅으로 form 전체를 제어하며,
모든 input은 register()를 통해 연결됩니다.
5. 기본적인 Validation
React Hook Form은 HTML의 기본 속성을 그대로 활용할 수 있습니다.
<input
{...register('password', {
required: '비밀번호를 입력해주세요.',
minLength: {
value: 6,
message: '비밀번호는 최소 6자 이상이어야 합니다.',
},
})}
/>
이처럼 required, minLength, pattern 등을 조합하여
입력 유효성 검사를 매우 간단히 구현할 수 있습니다.
6. 기본값 설정과 초기화
폼을 수정할 때 기존 데이터를 미리 넣어야 한다면
defaultValues 옵션을 사용하면 됩니다.
const { register, handleSubmit, reset } = useForm({
defaultValues: {
name: '홍길동',
email: 'hong@example.com',
},
});
const onReset = () => reset();
reset()을 호출하면 입력값을 초기 상태로 되돌릴 수도 있습니다.
7. watch – 실시간 입력 감지
watch()를 사용하면 특정 필드의 값을 실시간으로 감시할 수 있습니다.
const { register, watch } = useForm();
const password = watch('password', '');
이를 통해 비밀번호 일치 확인 기능 같은 것을 쉽게 구현할 수 있습니다.
<input type="password" {...register('password')} />
<input
type="password"
{...register('confirmPassword', {
validate: (value) => value === password || '비밀번호가 일치하지 않습니다.',
})}
/>
8. Controller – 커스텀 컴포넌트 제어
React Hook Form은 기본적으로 비제어 컴포넌트(uncontrolled) 기반입니다.
하지만 외부 UI 라이브러리(Material UI, Shadcn UI 등)를 사용할 때는
Controller를 사용해 제어할 수 있습니다.
import { Controller, useForm } from 'react-hook-form';
import { TextField } from '@mui/material';
function ProfileForm() {
const { control, handleSubmit } = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="nickname"
control={control}
defaultValue=""
render={({ field }) => (
<TextField {...field} label="닉네임" variant="outlined" />
)}
/>
<button type="submit">저장</button>
</form>
);
}
9. 외부 검증 라이브러리와 함께 사용하기 (Zod, Yup)
React Hook Form은 zod, yup과 쉽게 연동됩니다.
이 방식은 타입 안전성과 재사용성이 높아 실제 프로젝트에서 많이 사용됩니다.
npm install zod @hookform/resolvers
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
email: z.string().email('이메일 형식이 올바르지 않습니다.'),
password: z.string().min(6, '비밀번호는 6자 이상이어야 합니다.'),
});
function LoginForm() {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
});
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} placeholder="이메일" />
{errors.email && <p>{errors.email.message}</p>}
<input {...register('password')} placeholder="비밀번호" type="password" />
{errors.password && <p>{errors.password.message}</p>}
<button type="submit">로그인</button>
</form>
);
}
✅ resolver를 사용하면 zod 스키마 기반으로 유효성 검사를 자동화할 수 있습니다.
10. 마무리
React Hook Form은 리액트에서 폼을 다루는 가장 효율적인 방법입니다.
핵심 정리:
- register로 input을 손쉽게 등록
- errors로 유효성 검사 결과 확인
- watch, reset, Controller 등으로 세밀한 제어 가능
- Zod와 결합 시 강력한 타입 기반 검증 구현 가능
이제 더 이상 useState로 입력값을 일일이 관리할 필요가 없습니다.
다음 강의에서는 React Hook Form과 React Query를 결합하여
폼 데이터 전송과 서버 상태를 함께 관리하는 실전 예제를 다뤄보겠습니다.