TypeScript

React Hook Form: 폼 상태 관리

코샵 2025. 2. 19. 11:40
반응형

React Hook Form은 고성능의 유연한 폼 유효성 검사를 제공하는 라이브러리입니다. 불필요한 리렌더링을 최소화하고, 사용하기 쉬운 API를 제공합니다.

기본 설치 및 사용법

npm install react-hook-form
import { useForm } from 'react-hook-form';

interface FormInputs {
  email: string;
  password: string;
}

function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm<FormInputs>();

  const onSubmit = (data: FormInputs) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("email", { required: "이메일은 필수입니다" })} />
      {errors.email && <p>{errors.email.message}</p>}

      <input {...register("password", { 
        required: "비밀번호는 필수입니다",
        minLength: { value: 6, message: "최소 6자 이상이어야 합니다" }
      })} />
      {errors.password && <p>{errors.password.message}</p>}

      <button type="submit">로그인</button>
    </form>
  );
}

고급 유효성 검사

const SignupForm = () => {
  const { register, handleSubmit, watch, formState: { errors } } = useForm({
    defaultValues: {
      username: '',
      email: '',
      password: '',
      confirmPassword: ''
    }
  });

  const password = watch("password");

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <input {...register("username", {
        required: "사용자 이름은 필수입니다",
        pattern: {
          value: /^[A-Za-z0-9]+$/,
          message: "영문과 숫자만 사용 가능합니다"
        }
      })} />

      <input {...register("email", {
        required: "이메일은 필수입니다",
        pattern: {
          value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
          message: "유효한 이메일 주소를 입력하세요"
        }
      })} />

      <input {...register("confirmPassword", {
        validate: value => 
          value === password || "비밀번호가 일치하지 않습니다"
      })} />
    </form>
  );
};

폼 상태 관리

function ComplexForm() {
  const { 
    register, 
    handleSubmit, 
    formState: { 
      errors, 
      isSubmitting, 
      isDirty, 
      isValid 
    },
    reset,
    setValue,
    watch
  } = useForm({
    mode: 'onChange'
  });

  const onSubmit = async (data) => {
    try {
      await submitToServer(data);
      reset();
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* 폼 필드들 */}
      <button 
        type="submit" 
        disabled={!isDirty || !isValid || isSubmitting}
      >
        {isSubmitting ? '제출 중...' : '제출'}
      </button>
    </form>
  );
}

동적 폼 필드

function DynamicForm() {
  const { register, control, handleSubmit } = useForm();
  const { fields, append, remove } = useFieldArray({
    control,
    name: "items"
  });

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      {fields.map((field, index) => (
        <div key={field.id}>
          <input {...register(`items.${index}.name`)} />
          <input {...register(`items.${index}.quantity`)} />
          <button type="button" onClick={() => remove(index)}>
            삭제
          </button>
        </div>
      ))}

      <button type="button" onClick={() => append({ name: '', quantity: '' })}>
        항목 추가
      </button>
    </form>
  );
}

비동기 유효성 검사

function AsyncValidationForm() {
  const { register, handleSubmit, setError } = useForm();

  const validateUsername = async (username: string) => {
    const response = await fetch(`/api/check-username?username=${username}`);
    return response.ok;
  };

  return (
    <form>
      <input {...register("username", {
        validate: async value => {
          const isValid = await validateUsername(value);
          return isValid || "이미 사용 중인 사용자 이름입니다";
        }
      })} />
    </form>
  );
}

Schema 기반 유효성 검사

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';

const schema = z.object({
  name: z.string().min(2, "이름은 2자 이상이어야 합니다"),
  age: z.number().min(18, "18세 이상이어야 합니다"),
  email: z.string().email("유효한 이메일을 입력하세요")
});

function SchemaForm() {
  const { register, handleSubmit } = useForm({
    resolver: zodResolver(schema)
  });

  return (
    <form>
      <input {...register("name")} />
      <input {...register("age", { valueAsNumber: true })} />
      <input {...register("email")} />
    </form>
  );
}

 

장점

  1. 성능
    • 불필요한 리렌더링 방지
    • 제어 컴포넌트 최소화
  2. 사용성
    • 직관적인 API
    • 적은 보일러플레이트 코드
  3. 유연성
    • 다양한 유효성 검사 옵션
    • 커스텀 검증 로직 지원
  4. 타입 안전성
    • TypeScript 지원
    • 폼 데이터 타입 추론

React Hook Form은 복잡한 폼 상태 관리를 단순화하고, 높은 성능을 제공하는 강력한 도구입니다.