React hook form을 활용한 회원가입 폼 Validation 구현

디아·2022년 6월 10일
27
post-thumbnail
post-custom-banner

회원가입 기능을 구현할 때 유저로부터 이름, 이메일 주소, 비밀번호 등 여러가지 데이터를 입력 받아야 한다. state를 생성해서 입력받는 방법도 있겠지만 항목이 많을수록 그만큼 state를 여러 개 만들어야 하는 번거로움이 있다. 이를 개선해주는 React 라이브러리인 React-hook-form을 이용해서 회원가입 폼 유효성검사를 구현해보았다.

React hook form이란

Form의 Validation을 좀더 효율적으로 구현할 수 있게 도와주는 React 라이브러리이다.
다음의 장점을 가지고 있다.

  • 불필요한 리렌더링 방지
    - input에 변화가 있을때 form의 모든 요소가 리렌더링 되는 것이 아닌 입력받고 있는 input 요소만 리렌더링한다.
  • 빠른 component mounting 속도

React hook form으로 회원가입 폼 만들기

현재 만들고 있는 프로젝트의 회원가입 폼에는 총 4개의 input이 필요하다.

  • 닉네임
  • 이메일
  • 비밀번호
  • 비밀번호 확인

state를 사용했다면 각 항목별로 state를 모두 만들고, onChange 핸들러를 각각 만들어야 하는 번거로움이 있지만 React-hook-form을 사용하여 좀 더 간단하게 구현할 수 있었다.

1. useForm() hook을 사용하여 필요한 함수, 객체 불러오기

// form에 사용되는 데이터 타입 정의
interface IAuthForm {
  nickname: string;
  email: string;
  pw: string;
  pwConfirm: string;
}

const {
    register,
    formState: { errors },
    handleSubmit,
    setError,
  } = useForm<IAuthForm>({mode: 'onBlur'});
Methods / FunctionsDescription
registerinput 요소를 React hook form과 연결시켜 검증 규칙을 적용할 수 있게 하는 메소드
formStateform state에 관한 정보를 담고 있는 객체
handleSubmitform을 submit했을 때 실행할 함수. Validation을 통과했을때 실행할 콜백함수(SubmitHandler)가 반드시 필요하다. 실패했을때의 콜백함수(SubmitErrorHandler)는 옵셔널.
setErrorerror 관련 설정에 사용되는 함수

onBlur 이벤트 발생할 때 validation 발생시키기

사용자가 submit 버튼을 누르기 전에 form에 입력한 값이 유효한 값이 아니라는 것을 미리 표시해주는 것이 좀 더 나은 UX를 제공한다고 생각하는데, 이를 가능하게 해주는 것이 mode이다.
modeuseForm()에 넘겨줄 수 있는 다양한 optional arguments 중 하나로 사용자가 form을 submit 하기 전에 validation이 실행될 수 있게 해준다.

// mode에 사용 가능한 값
mode: onChange | onBlur | onSubmit | onTouched | all = 'onSubmit'
//onBlur 이벤트가 발생할때마다 validation이 실행된다.
const { register } = useForm({mode: 'onBlur'})

2. input 요소를 React hook form에 등록하기

register 메소드를 사용해서 input 요소를 React hook form에 등록한다.
register는 객체를 반환하기 때문에 스프레드 문법을 사용해서 props로 전달해줘야 준다. 인자로 input 요소의 name으로 사용될 string 값을 써준다.

register: (name: string, RegisterOptions?) => ({ onChange, onBlur, name, ref })

const AuthForm = () => {
  
  // ...
  
  return (
    <form>
      <fieldset>
        <legend>회원가입</legend>
        <label htmlFor="nickname">닉네임</label>
        <input {...register("nickname")} />
        <label htmlFor="email">이메일</label>
        <input {...register("email")} />
        <label>비밀번호</label>
        <input {...register("pw")} />
        <label>비밀번호 확인</label>
        <input {...register("pwConfirm")} />
      </fieldset>
    </form>
  )
}

Validation 옵션 주기

option nameDescription
required필수 입력 항목 지정할 때 사용할 수 있다. boolean값도 가능하지만 문자열 값을 주면, input의 value가 없을 때 해당 문자열이 errors 객체로 반환되어 에러 메세지로 표시할 수 있다.
minLengthvalue의 최소 길이
patterninput 입력값에 적용할 정규식 패턴
validatevalidate 함수를 직접 만들어서 validation을 할 수 있다.
대부분의 validation 옵션들은 string, string[], number, boolean 타입 데이터에 해당되므로, 객체나 배열 input 데이터의 경우, validate 함수를 사용하는 것이 권장된다.(참고)
<input
  {...register('nickname', {    
    required: '닉네임을 입력해주세요.',
    // required: true,
    // boolean값도 가능하지만 문자열 값을 주면, input의 value가 없을 때 해당 문자열이 errors 객체로 반환되어 에러 메세지로 표시할 수 있다.
    minLength: { // value의 최소 길이
      value: 3,
      message: '3글자 이상 입력해주세요.', // 에러 메세지
    },
    pattern: { // input의 정규식 패턴
      value: /^[A-za-z0-9가-힣]{3,10}$/,
      message: '가능한 문자: 영문 대소문자, 글자 단위 한글, 숫자', // 에러 메세지
    },
  })}
  placeholder="닉네임을 입력해주세요"
  />
<p>{errors?.nickname?.message}</p> // validation fail 시 에러 메세지 표시


// validate 예시
<input 
  {...register("test1", {
    validate: {
      checkUrl: async () => await fetch() || 'error message',
      messages: v => !v && ['test', 'test2']
    }
  })}
/>

3. handleSubmit 함수를 onSubmit props로 넘겨주기

handleSubmit 함수의 인자로 반드시 SubmitHandler(validation 통과 됐을때의 콜백함수)를 써준다. 콜백함수가 비동기 함수인 경우 handleSubmit 함수가 따로 에러 핸들링을 하지 않으므로 try...catch 로 에러 핸들링을 해준다.

const AuthForm = () => {
  
  const {
    //...
    handleSubmit,
    setError
  } = useForm<IAuthForm>({mode: 'onBlur'});
  
  // SubmitHandler
  const onValid = (data : IAuthForm) => {
	console.log("성공!")
  }
  
return (
  // handleSubmit함수를 onSubmit props로 보내준다
  <form onSubmit={handleSubmit(() => { 
  	try {
      onValid()
    }catch(e){
      console.log(e)
    }
  
  )}>
    <fieldset>
      <legend>회원가입</legend>

      // ...

    </fieldset>
  </form>
  )
}

4. setError 함수를 사용한 에러 핸들링

const AuthForm = () => {
  
  const {
    //...
    handleSubmit,
    setError,
  } = useForm<IAuthForm>({mode: 'onBlur'});
    
  const onValid = (data : IAuthForm) => {
	if (data.pw !== data.pwConfirm) {      
      setError(
        'pwConfirm', // 에러 핸들링할 input요소 name
        { message: '비밀번호가 일치하지 않습니다.' }, // 에러 메세지
        { shouldFocus: true }, // 에러가 발생한 input으로 focus 이동
      );
    }
  }
  
return (
  <form onSubmit={handleSubmit(() => { 
  	try {
      onValid()
    }catch(e){
      console.log(e)
    }  
  )}>
    <fieldset>
      <legend>회원가입</legend>
                                 
      // ...
                                 
      <label>비밀번호</label>                                 
      <input {...register("pw")} />
      <label>비밀번호 확인</label>
      <input {...register("pwConfirm")} />
    </fieldset>
  </form>
  )
}


전체코드

profile
얼레벌레 프론트엔드 개발자
post-custom-banner

0개의 댓글