react-hook-form 사용하기

uk·2023년 9월 4일
0

React

목록 보기
17/17

react-hook-form이란?

React 애플리케이션에서 form 관리를 간편하게 해주는 라이브러리이다.

제어 컴포넌트를 통해 form을 관리하면 사용자 입력을 처리하기 위한 state를 하나하나 만들어야 하고 이를 다루기 위한 이벤트 핸들러, 에러 처리를 위한 state, 유효성 검사 등 코드량이 증가하고 가독성이 떨어진다.

또한 React에서 state가 변경되면 리렌더링이 발생하기 때문에 입력 값이 변경될 때마다 여러 자식 컴포넌트에서 많은 리렌더링이 발생하고 성능이 저하된다.

react-hook-form을 사용하면 form 상태를 관리 및 유효성 검사, 에러 처리에 필요한 코드를 대폭 줄이고 불필요한 렌더링을 방지하여 성능을 향상 시킬 수 있다.


react-hook-form의 장점

  1. 간결한 API를 제공하며 복잡한 form 로직을 단순화한다. 비제어 컴포넌트 방식으로 구현하기 때문에 컴포넌트에서 관리되는 state가 줄어들고 비동기적으로 동작하는 setState의 의도하지 않은 동작을 최소화할 수 있다.

  2. 사용자 입력 값이 변경됨에 따라 발생하는 불필요한 리렌더링을 방지하여 렌더링 성능을 최적화한다.

  3. react-hook-form에 내장된 유효성 검사를 수행하고 erros 객체를 통해 에러 메세지를 표시할 수 있다.

  4. 커스텀 훅과 결합하여 개발자가 필요한 로직을 쉽게 작성하고 재사용할 수 있도록 지원한다.


react-hook-form 사용하기

  const {
    register,
    handleSubmit,
    formState: { 
      errors,
      isSubmitSuccessful,
    },
    setError,
    setFocus,
    watch,
    reset,
    trigger,
  } = useForm<FormData>({
    mode: 'onSubmit',
    defaultValues: { id: '', pw: '' },
  });

useForm

useForm은 form 인스턴스를 생성하고 validation(유효성 검사) 전략과 초기값을 설정할 수 있다.

mode - validation을 언제 수행할지 설정하며 해당 이벤트가 발생하면 유효성 검사가 수행된다.

  • all - onBlur + onChange
  • onBlur - 해당 input에 커서를 위치시켰다가 input을 벗어난 곳을 클릭할 때
  • onChange - form 입력값이 변경될 때마다
  • onSubmit - form 제출 시
  • onTouched - 첫 blur 이벤트 후 onChange 이벤트가 발생할 때마다

-> all, onChange 옵션은 잦은 리렌더링이 발생하기 때문에 성능이 저하될 수 있다.

defaultValues - form의 초기값을 설정
-> 초기값을 설정하지 않는 경우 input의 초기값은 undefined로 관리된다.


register

return (
  <input
    type='text'
    {...register('id', {
      required: 'id는 필수 입력 값입니다.',
      minLength: {
        value: 2,
        message: '2글자 이상 입력하세요.',
      },
      pattern: {
        value: /^[A-za-z0-9ㄱ-ㅎㅏ-ㅣ가-힣]{2,10}$/,
        message: '영문, 한글, 숫자 2~10자리만 입력 가능합니다.',
      },
    })}
  />
);

register는 입력 필드(input)를 다루고 해당 필드를 react-hook-form에 연결하는 함수이다.

첫번째 매개변수로 name이 필요하며 해당 필드를 관리하는 key값이다.

두번째 매개변수로 options 객체가 들어가며 유효성 검사 옵션을 설정할 수있다.

  • required - 입력값 필수 여부
  • min - number 타입 입력값의 최소값
  • max - number 타입 입력값의 최대값
  • minLength - string 타입 입력값의 최소 길이
  • maxLength - string 타입 입력값의 최대 길이
  • pattern - 정규식을 이용한 유효성 검사
  • validate - 사용자 정의 유효성 검사

value를 통해 옵션값을 설정하며 message를 통해 에러 메세지를 출력할 수 있다.

trigger

// 모든 입력 필드를 validation
<button type="button" onClick={() => trigger()}>
  Validate
</button>

// 특정 입력 필드만 validation
<button type="button" onClick={() => trigger('id')}>
  Validate
</button>

// 여러 입력 필드를 validation
<button type="button" onClick={() => trigger(['id', 'pw'])}>
  Validate
</button>

버튼을 클릭하면 수동으로 Validation을 수행할 수 있다.


handleSubmit

const onSubmit: SubmitHandler<FormData> = (data) => {
  ...
};

return (
  <form onSubmit={handleSubmit(onSubmit)}>
    ...
  </form>
);

handleSubmit은 form 제출(submit) 시 실행되는 함수로 유효성 검사를 수행하고 최종적으로 제출할 데이터를 처리하는 함수를 매개변수로 받는다.

onSubmit 함수는 매개변수로 data라는 값을 받으며 사용자가 최종 제출하는 데이터이다.


formState, errors

{errors.id && <p className='error'>{errors.id.message}</p>}

formState: { errors }는 해당 필드에 대한 에러 정보를 가지고 있으며 유효성 검사 실패 시 에러 타입이나 에러 메세지를 표시할 수 있다.
-> 에러가 존재하지 않으면 errors 객체는 빈 객체이다.

formState는 에러 정보 뿐만 아니라 특정 form 상태에 관한 여러 정보를 제공한다.

  • touchedFields - 사용자에 의해 수정된 필드 목록
  • dirtyFields - 초기값이 수정된 필드 목록
  • isDirty - form 내용 변경 여부
  • isSubmitted - form 제출 여부
  • isSubmitting - form이 제출 중인지 여부
  • submitCount - form의 제출 횟수
  • isValid - form의 유효(에러) 여부
  • isValidating - form의 유효성 검사 진행 여부

watch

const { register, watch } = useForm();

const idValue = watch('id');

return (
  <form>
    <input
      type='text'
      {...register('id', {
        // options
      })}
    />
    <p>{idValue}</p>
  </form>
  );

watch는 특정 form에 입력된 값을 감시하고 실시간으로 체크할 수 있게 해주는 함수이다.

watch 함수를 통해 입력된 값을 감시하고 반환할 때마다 리렌더링이 발생한다.


reset

  useEffect(() => {
    if (isSubmitSuccessful) {
      reset();
    }
  }, [isSubmitSuccessful, reset]);

<button type='button' onClick={() => reset()}>
  Clear
</button>

reset 함수는 Submit 후 form에 입력된 값을 defaultValues 값으로 초기화 시켜준다. useEffect 훅과 formState의 isSubmitSuccessful 상태값을 이용해 reset 함수를 실행한다.

사용자가 직접 버튼을 눌러 입력된 값을 초기화 시킬 수도 있다.


전체 코드

import { SubmitHandler, useForm } from 'react-hook-form';

interface FormData {
  id: string;
  pw: string;
}

export default function MyForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
    setError,
    setFocus,
    watch,
  } = useForm<FormData>({
    mode: 'onSubmit',
    defaultValues: { id: '', pw: '' },
  });

  const idValue = watch('id');
  
  const onSubmit: SubmitHandler<FormData> = (data) => {
     if (data.id.length < 2) {
      setError('id', { type: 'minLength', message: '2글자 이상 입력하세요.' });
      setFocus('id');
    }
    if (data.pw.length < 4) {
      setError('pw', { type: 'minLength', message: '4글자 이상 입력하세요.' });
      setFocus('pw');
    }
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input
        type='text'
        {...register('id', {
          required: 'id는 필수 입력 값입니다.',
          minLength: {
            value: 2,
            message: '2글자 이상 입력하세요.',
          },
          pattern: {
            value: /^[A-za-z0-9ㄱ-ㅎㅏ-ㅣ가-힣]{2,10}$/,
            message: '영문, 한글, 숫자 2~10 자리만 입력 가능합니다.',
          },
        })}
      />
      {errors.id && <p className='error'>{errors.id.message}</p>}

      <input
        type='text'
        {...register('pw', {
          required: 'pw는 입력값은 필수입니다',
          minLength: {
            value: 4,
            message: '4글자 이상 입력하세요',
          },
          pattern: {
            value: /^[A-za-z0-9ㄱ-ㅎㅏ-ㅣ가-힣]{4,10}$/,
            message: '영문, 한글, 숫자 4~10 자리만 입력 가능합니다.',
          },
        })}
      />
      {errors.pw && <p className='error'>{errors.pw.message}</p>}
       
      <button type='submit'>Submit</button>
      <button type='button' onClick={() => reset()}>
        Clear
      </button>
      <p>입력된 값: {idValue}</p>
    </form>
  );
}
profile
주니어 프론트엔드 개발자 uk입니다.

0개의 댓글