frontend/react

[React] React.js 강좌 15. React Hook Form 완벽 가이드 – 폼 관리의 혁신

mirabo01 2025. 11. 10. 08:52

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를 결합하여
폼 데이터 전송과 서버 상태를 함께 관리하는 실전 예제를 다뤄보겠습니다.