Home React Hook Form
Post
X

React Hook Form

React Hook Form

React에서 폼(form) 상태와 검증을 쉽게 관리할 수 있게 해주는 라이브러리입니다.

1
npm install react-hook-form

  • 최소한의 리렌더링 : 입력할 때마다 전체 컴포넌트가 리렌더링되지 않음

  • 간편한 validation : 외부 validation 라이브러리(Zod, Yup)와 쉽게 통합 가능

  • 성능 최적화 : register로 각 input만 상태를 추적하기 때문에 불필요한 렌더링을 줄임

  • TypeScript 친화적 : 제네릭으로 타입 안전하게 폼 데이터를 관리 가능


useForm

1
const methods = useForm<FormDataType>(options);

useForm 주요 옵션

  • defaultValues (object) : 폼 필드의 초기 값 설정

  • resolver (function) : 외부 validation 라이브러리(Zod, Yup 등) 연결

  • mode : validation을 언제 실행할지를 결정, 기본값은 ‘onSubmit’

    • ‘onSubmit’ : 폼 제출 시 (default)
    • ‘onBlur’ : input에서 focus를 잃을 때
    • ‘onChange’ : 입력이 바뀔 때마다
    • ‘all’ : onBlur + onChange 모두
  • reValidateMode : 이미 에러가 발생한 필드가 다시 validation 될 타이밍을 설정, 기본값은 ‘onSubmit’

    • ‘onChange’ : 에러 난 필드의 값이 바뀔 때마다 (default)
    • ‘onBlur’ : 에러 난 필드가 blur 될 때만
    • ‘onSubmit’ : 에러 난 필드도 submit 시에만
  • criteriaMode : 한 필드에서 여러 validation 규칙을 걸었을 때 어떻게 에러를 보여줄지 결정, 기본값은 ‘firstError’

    • ‘firstError’ : 첫 번째 에러만 보여줌 (default)
    • ‘all’ : 모든 에러 메시지를 배열로 반환
  • shouldFocusError (boolean) : 에러 발생 시, 에러가 있는 첫 번째 필드로 포커스 이동 여부를 결정

  • shouldUnregister (boolean) : 언마운트 시 필드 값 제거 여부 (default: true)

1
2
3
4
5
6
7
8
9
10
11
const { register, handleSubmit, formState } = useForm<LoginFormData>({
  defaultValues: {
    id: "",
    password: "",
  },
  resolver: zodResolver(loginSchema),
  mode: "onBlur", // blur 시 validation
  criteriaMode: "firstError", // 첫 번째 에러만 보여줌
  shouldFocus
  Error: true,
});

useForm 핵심 메서드

useForm()은 주요 메서드들이 들어있는 객체를 반환합니다.


폼 관리 관련

  • register : input 요소를 RHF와 연결하는 메서드 (필수)

    첫 번째 인자: 필드 이름 (‘email’) 두 번째 인자: 유효성 검사 규칙 (required, minLength, validate 등)

    1
    
    <input {...register("email", { required: "이메일은 필수입니다." })} />
    
  • unregister : input field 등록 해제
  • setValue(name, value) : 필드 값 직접 설정
  • getValues() : 현재 폼 값 가져오기
  • reset(values?) : 폼 초기화, 옵션으로 값 지정 가능

    1
    2
    
    reset(); // defaultValues로 리셋
    reset({ email: "", password: "" }); // 새 값으로 리셋
    
  • watch(name?) : 특정 필드 값 관찰, 실시간으로 값 가져오기

제출 관련

  • handleSubmit(onValid, onInvalid?) : form submit 처리, validation 성공 시 onValid 호출, 실패 시 onInvalid 호출

    1
    2
    3
    
    const onSubmit = (data: LoginFormData) => console.log(data);
    
    <form onSubmit={handleSubmit(onSubmit)} />;
    
  • trigger(name) : 수동으로 유효성 검사 실행

    1
    2
    
    await trigger(); // 전체 필드 검사
    await trigger("email"); // 특정 필드만 검사
    

폼 상태 관련 (formState)

formState 객체를 반환

  • errors : 필드별 validation 에러 객체
  • isSubmitting : 제출 중 여부 (submit 버튼 disable 처리 가능)
  • isSubmitSuccessful : 제출 성공 여부 (submit 버튼 disable 처리 가능)
  • isDirty : 하나라도 폼 값이 변경되었는지 여부
  • dirtyFields : 값이 변경된 필드 정보
  • isValid : 폼 전체가 유효한지 여부
  • touchedFields : focus 후 blur된 필드 정보
1
2
3
const {
  formState: { errors, isSubmitting, isValid },
} = useForm();

useForm 사용 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const {
  register, // input 등록
  handleSubmit, // submit 처리
  watch, // 값 감시
  setValue, // 값 설정
  getValues, // 값 가져오기
  reset, // 초기화
  unregister, // 등록 해제
  formState: {
    errors, // validation 에러
    isSubmitting, // 제출 중
    isDirty, // 값 변경 여부
    isValid, // 유효성 여부
    touchedFields, // 포커스 후 blur 된 필드
    dirtyFields, // 값 변경된 필드
  },
} = useForm<LoginFormData>({
  defaultValues: { id: "", password: "" },
  resolver: zodResolver(loginSchema),
  mode: "onBlur",
  shouldFocusError: true,
});

기본 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { useForm } from "react-hook-form";

type FormData = {
  username: string;
  password: string;
};

const MyForm = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormData>();

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

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("username", { required: "아이디를 입력하세요" })} />
      {errors.username && <span>{errors.username.message}</span>}

      <input
        type="password"
        {...register("password", { required: "비밀번호를 입력하세요" })}
      />
      {errors.password && <span>{errors.password.message}</span>}

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

응용 - 외부 validation 라이브러리 연결

Zod와 함께 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// zodResolver
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

const loginSchema = z.object({
  id: z.string().min(1, "아이디를 입력하세요"),
  password: z.string().min(6, "비밀번호는 6자리 이상입니다"),
});

type LoginFormData = z.infer<typeof loginSchema>;

const {
  register,
  handleSubmit,
  formState: { errors },
} = useForm<LoginFormData>({
  resolver: zodResolver(loginSchema),
});
  • zodResolver가 Zod schema를 RHF에 연결
  • safeParse처럼 별도로 에러를 매핑할 필요 없음
  • errors 객체에 자동으로 필드별 메시지가 들어옴
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.