조각조각 - react-hook-form

eocode·2023년 3월 16일
0

리액트 조각조각

목록 보기
4/11
post-thumbnail

지금까지 입력 폼을 사용할때 입력 폼 하나 당 state와 useState 훅을 이용해서 사용해왔습니다. 반복적인 코드 및 리렌더링이 많이 발생한다는 문제점을 생각하던 중 전 팀프로젝트에서 react-hook-form를 알게되었습니다. 맛보기만 해보았는데 상당히 유용하다고 느꼈습니다. 덕분에 다음 프로젝트에는 react-hook-form을 사용하기로 마음먹어 이번에 정리해보도록 하겠습니다.

⌨️ 기존에 사용하던 입력 폼 활용 방식
입력 폼 마다 state, useState 훅이 사용됩니다. 따라서 입력 폼의 onChange 이벤트가 발생할때마다 state 변경이 발생하고 리렌더링이 발생합니다.

const InputExam = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [nick, setNick] = useState("");
  
  const handleEmail = (e: React.ChangeEvent<HTMLInputElement>) => {
    setEmail(e.target.value);
  };
  const handlePassword = (e: React.ChangeEvent<HTMLInputElement>) => {
    setPassword(e.target.value);
  };
  const handleNick = (e: React.ChangeEvent<HTMLInputElement>) => {
    setNick(e.target.value);
  };

  return (
    <>
      <input placeholder="이메일" onChange={handleEmail}></input>
      <input placeholder="닉네임" onChange={handleNick}></input>
      <input placeholder="비밀번호" onChange={handlePassword}></input>
      ...
    <>
  )
}

react-hook-form

정의

react-hook-form은 입력 폼을 관리하기 위한 라이브러리로 기존의 입력 폼, state, useState 방식에서는 반복적인 코드 및 리렌더링 문제점을 해결할 수 있습니다.
react-hook-form은 useForm 훅을 제공하며, useForm 훅은 register, formState, watch, reset, handleSubmit, getValues, setError, setFocus 등의 함수를 반환하여 입력 폼을 유용하게 관리하도록 도와줍니다.

설치

npm i react-hook-form

useForm 훅

리턴 함수

  • register : validation을 위한 함수
  • formState : form 관련 값
  • watch : 입력폼 값 얻기위한 함수(상시)
  • getValue : 입력폼 값 얻기위한 함수
  • setError : 에러 처리
  • handleSubmit : form submit 처리

사용법

회원가입 폼을 예시로 알아보겠습니다.

interface SignInForm {
  email: string;
  nickname: string;
  password: string;
  passwordCheck: string;
}

...

  const {
    register,
    formState: { errors },
    watch,
    reset,
    handleSubmit,
    getValues,
    setError,
    setFocus
  } = useForm<SignInForm>({
    mode: "onBlur",
    defaultValues: {
      email: "",
      nickname: "",
      password: "",
      passwordCheck: ""
    }
  });

useForm 훅을 이용해 register, formState, watch, reset, handleSubmit, getValues, setError, setFocus 함수를 받아옵니다. 이때 useForm 훅의 인자로 {mode : ..., defaultValues: ...} 객체가 입력되는데 mode의 값은 onSubmit, onChange, onBlur, all이며 각각은 언제 validation이 동작할지를 결정합니다. defaultValues는 폼에서 입력되는 값의 기본 값을 뜻합니다.

🚨 위 코드는 타입스크립트로 작성되었기때문에 interface로 기본값의 형태를 정해주었습니다.

  • onSubmit : form에서 submit 버튼이 눌렸을 경우
  • onChange : 폼의 입력 값이 변경되는 경우
  • onBlur : 폼의 포커스가 해제된 경우
<input
  placeholder="이메일"
  type="text"
  {...register("email", {
    required: {
      value: true,
      message: "이메일을 입력해주세요."
    ,
    maxLength: {
      value: 30,
      message: "최대 30자 입력가능합니다."
      },
    pattern: {
      value: /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i,
      message: "이메일 형식에 맞지 않습니다."
      }
   })}></input>

register 함수를 사용하여 input 태그를 다룹니다. (register의 반환값을 스프레드 문법으로 처리) regiter 함수의 첫번째 인자는 폼의 입력되는 값의 이름(key값으로 반드시 필요), 두번째 인자는 validation에 필요한 조건 객체입니다. 객체의 값들은 required, minLength, maxLength, pattern 등의 값을 가지며 필수여부, 최소 길이, 최대 길이, 형식 등을 정의합니다.

위 코드의 경우 "email" 이름을 가진 폼의 값이 required value가 true이므로 필수이며 또 maxLength로 최대 길이 30자, pattern에 입력된 정규식과 같은 형태를 가져야 합니다. 만약 올바르지 않은 값이 입력된 경우 message에 해당하는 문구의 값을 formData 객체 내부 message가 가지게 됩니다.

formData.폼의이름.errors.message : "이메일을 입력해주세요."
formData.폼의이름.errors.message : "최대 30자 입력가능합니다."
formData.폼의이름.errors.message : "이메일 형식에 맞지 않습니다."

비밀번호 일치 확인

useForm mode에 설정된 값으로 처리
<input placeholder="비밀번호 확인"
  type="password"
  {...register("passwordCheck", {
    required: {
      value: true,
      message: "비밀번호를 입력해주세요."
    },
    minLength: {
      value: 8,
      message: "최소 8자 이상 입력해주세요."
    },
    maxLength: {
      value: 30,
      message: "최대 30자 입력가능합니다."
    },
    pattern: {
      value: /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/i,
      message: "최소 8 자, 최소 하나의 문자 및 하나의 숫자"
    },
    validate: (value: string) => {
      if (watch("password") != value) {
        return "비밀번호가 일치하지 않습니다.";
    }
  }
})}></input>

회원가입에서 비밀번호 확인을 위해 이전 폼에서 입력된 값과 일치하는지 확인하는 과정이 필요합니다. 이 경우 위 코드의 pattern만으로 처리가 불가능합니다. 이때 validate 함수를 사용하여 해결 가능합니다.

register 함수의 두번째 인자 객체에 watch 함수를 이용해 폼에 입력된 값을 가져와 비교하는 validate 함수를 입력합니다.

setError를 이용해 특정 시점에 비밀번호 확인 처리

위 코드의 경우 다른 입력 폼들처럼 폼에서 포커스가 사라질때 validation이 동작합니다. 즉 비밀번호 재입력 폼에서 포커스가 벗어날때마다 비밀번호가 일치하는지 확인하게 됩니다.(또는 mode가 onChange라면 비밀번호 재입력 폼이 입력될때마다 비교) 이 경우 효율성이 떨어질 수 있습니다.

이런 문제를 극복하기 위해 submit 버튼이 눌린 경우에만 재입력된 비밀번호가 일치하는지 확인하도록 하는것도 가능합니다.

  const isPasswordSame = () => {
    const pw = getValues("password");
    const pwc = getValues("passwordCheck");
    if (pw !== pwc) {
      setError(
        "passwordCheck",
        { message: "비밀번호가 일치하지 않습니다." },
        { shouldFocus: true }
      );
    }
  };

...

<LogInSignUp.Form onSubmit={handleSubmit(onSubmit)}>
  
...

submit 버튼 클릭시 동작하는 함수안에서 getValues 함수를 이용해 폼에 입력된 값들을 가져오고 비교, 두 비밀번호가 일치하지 않는 경우 setError 함수를 통해 formData의 errors.message 설정하여 활용 가능합니다.

참고 자료

profile
프론트엔드 개발자

0개의 댓글