react-hook-form 알고 쓰자

kim yeseul·2023년 5월 11일
3

라이브러리

목록 보기
3/6
post-thumbnail

➡️ 먼저 react-hook-form이란 무엇인가?

Performant, flexible and extensible forms with easy-to-use validation.
유효성 검사를 쉽게 할 수 있는, 성능이 우수하고 유연하며 확장 가능한 form을 제공하는 라이브러리이다.

➡️ react-hook-form 라이브러리를 사용하는 이유는 뭘까? (장점)

  1. 성능
    : Formik이나 Redux Form보다 속도가 훨씬 빠르다
    (React Hook Form: 3800ms < Formik: 5800ms < Redux Form: 16000ms)

참고 링크
https://github.com/react-hook-form/performance-compare

  1. 소스 코드가 깔끔하다.
    : 코드 길이가 다른 라이브러리보다 짧아 syntax가 깔끔하고, 리액트 본연의 syntax와 비슷하여 사용하기 편리하다.

  2. 비제어 컴포넌트 방식의 사용으로 불필요한 렌더링을 막아주어 속도가 빠르다.
    -> 여기서 리액트의 제어 컴포넌트와 비제어 컴포넌트에 대해 알아야 할 필요가 있다.

🧐 제어 컴포넌트 ?

HTML에서 <input>, <textarea>, <select>와 같은 폼 엘리먼트는 일반적으로 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트합니다. React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState()에 의해 업데이트됩니다.
...
폼을 렌더링하는 React 컴포넌트는 폼에 발생하는 사용자 입력값을 제어합니다. 이러한 방식으로 React에 의해 값이 제어되는 입력 폼 엘리먼트를 “제어 컴포넌트 (controlled component)“라고 합니다.

위는 공식 문서의 제어 컴포넌트의 설명이다이다.
https://ko.legacy.reactjs.org/docs/forms.html#controlled-components

간단히 말하자면, state가 렌더링을 제어하는 것을 제어 컴포넌트라고 하는데 onChange 방식이 제어 컴포넌트라고 할 수 있다.

const UseInput = () => {
  const [input, setInput] = useState("");
  const onChangeValue = (e) => {
    setInput(e.target.value);
  };

  return (
    <div>
      <input onChange={onChangeValue} />
    </div>
  );
}

export default UseInput;

사용자가 입력한 값과 저장되는 값이 실시간으로 동기화 된다.
이러한 방식으로 데이터를 전부 받아올 수 있어 유효성 검사에 탁월한데
데이터를 하나하나 다 받아오므로 비효율적이거나 속도가 느릴 수 있는 단점이 있다.

🧐 비제어 컴포넌트 ?

대부분 경우에 폼을 구현하는데 제어 컴포넌트를 사용하는 것이 좋습니다. 제어 컴포넌트에서 폼 데이터는 React 컴포넌트에서 다루어집니다. 대안인 비제어 컴포넌트는 DOM 자체에서 폼 데이터가 다루어집니다.

모든 state 업데이트에 대한 이벤트 핸들러를 작성하는 대신 비제어 컴포넌트를 만들려면 ref를 사용하여 DOM에서 폼 값을 가져올 수 있습니다.

위는 공식 문서의 비제어 컴포넌트의 설명이다.
https://ko.legacy.reactjs.org/docs/uncontrolled-components.html

import React, { useRef } from 'react';

const UseRefInput = () => {
  const inputRef = useRef(null);
  const onSubmit = () => {
    console.log(inputRef.current.value);
  };

  return (
    <div>
      <input ref={inputRef} />
	  <button type="submit" onClick={onSubmit}>
        로그인
      </button>
    </div>
  );
}

export default UseRefInput;

ref는 값을 업데이트 하여도 리랜더링 되지 않는 특성으로, 입력이 모두 되고난 후 ref를 통해 값을 한번에 가져와서 활용한다.
state로 값을 관리하지 않기 때문에 값이 바뀔 때마다 리랜더링을 하지 않고 값을 한번에 가져올 수 있는 성능상 이점이 있으나, 데이터를 완벽하게 가져올 수 없는 단점이 있다.

react hook form은 비제어 컴포넌트로 렌더링을 최적화할 수 있는 라이브러이다.
단순한 form을 처리하기 위해 state로 모든 값을 검사하여 리랜더링 하는 것보다 입력이 끝난 후 유효성 검사를 보여주어도 되고 더 빠른 검사를 할 수 있어 비제어 컴포넌트 방식인 react hook form을 많이 사용하는 것이라 생각한다.

➡️ 어떻게 사용하는가?

1. 시작: npm, yarn 으로 설치하기
npm install react-hook-form
yarn add react-hook-form

2. useForm import하여 사용하기

import { useForm } from "react-hook-form";

const {
    handleSubmit, // form onSubmit에 들어가는 함수
    register, // onChange 등의 이벤트 객체 생성
    watch, // register를 통해 받은 모든 값 확인
    formState: { errors }, // errors: register의 에러 메세지 자동 출력
  } = useForm();

3. 회원가입 유효성 검사

import * as S from "./style";
import BasicButton from "../../../components/Button/Button";
import { useForm } from "react-hook-form";
import { useRef } from "react";
const SignUpForm = () => {
  const {
    handleSubmit, // form onSubmit에 들어가는 함수
    register, // onChange 등의 이벤트 객체 생성
    watch, // register를 통해 받은 모든 값 확인
    formState: { errors }, // errors: register의 에러 메세지 자동 출력
  } = useForm();


  const password = useRef(); // ref 생성
  password.current = watch("password"); // watch를 이용하여 password 필드 값 가져오기, password.current에 값 넣어주기

  const onChangeFormLib = (data) => {
    console.log("회원가입 정보", data);
  };

  return (
    <S.Form onSubmit={handleSubmit(onChangeFormLib)}>
      <S.InputBox>
        <label>이메일 </label>{" "}
        <input
          {...register("email", {
            required: { value: true, message: "이메일을 입력해주세요" },
            pattern: {
              value: /^\S+@\S+$/i,
              message: "이메일 형식이 올바르지 않습니다",
            },
          })}
        />
      </S.InputBox>
      {errors?.email && <S.ErrMsg>{errors?.email?.message}</S.ErrMsg>}
      <S.InputBox>
        <label>비밀번호 </label>{" "}
        <input
          name="password"
          type="password"
          {...register("password", {
            required: { value: true, message: "비밀번호를 입력해주세요" },
            minLength: {
              value: 8,
              message: "비밀번호 길이를 8자리 이상 입력해주세요",
            },
          })}
        />
      </S.InputBox>
      {errors.password && <S.ErrMsg>{errors?.password?.message}</S.ErrMsg>}
      <S.InputBox>
        <label>비밀번호 확인 </label>{" "}
        <input
          name="passwordConfirm"
          type="password"
          {...register("passwordConfirm", {
            required: { value: true, message: "비밀번호 확인을 입력해주세요" },
            validate: (value) => value === password.current, // password와 passwordConfirm이 같은지 체크하는 부분
          })}
        />
      </S.InputBox>
      {errors?.passwordConfirm?.type === "required" && (
        <S.ErrMsg>{errors?.passwordConfirm?.message}</S.ErrMsg>
      )}
      {errors?.passwordConfirm?.type === "validate" && (
        <S.ErrMsg>비밀번호가 일치하지 않습니다.</S.ErrMsg>
      )}
      <BasicButton
        variant={"primary"}
        shape={"default"}
        size={"full"}
      >
        회원가입
      </BasicButton>
    </S.Form>
  );
};

export default SignUpForm;

1. register

입력 또는 선택 요소를 등록하고 React Hook Form에 유효성 검사 규칙을 적용할 수 있다.

예를 들어, 아래와 같이 ...register(검사할 속성 이름, 검사 패턴, 필수 속성 등) 를 작성하여 이름을 등록 후 두번째 인자로 받은 속성들로 유효성 검사를 할 수 있다.

<input
  {...register("email", {
     required: { value: true, message: "이메일을 입력해주세요" },
     pattern: {
     value: /^\S+@\S+$/i,
     message: "이메일 형식이 올바르지 않습니다",
     },
  })}
/>

위 유효성 검사는 input은 email 유효성을 검사하는 것이고, 필수 속성이며 값을 입력하지 않으면 '이메일을 입력해주세요'라는 메세지가 나온다. 또 value의 pattern 에 맞는 형식이어야 하며 형식에 어긋나게 되면 '이메일 형식이 올바르지 않습니다' 라는 에러 메세지를 뱉어준다.

2. errors

formState: { errors } 속성을 통해 위에서 검사한 값이 어긋나면 에러 메세지를 아래처럼 사용할 수 있다.

{errors?.email && <S.ErrMsg>{errors?.email?.message}</S.ErrMsg>}

이 외에도 다양한 속성을 적용하여 더 깊은 유효성 검사를 할 수 있다.

😵 그런데, 해당 컴포넌트에서 유효성 검사를 하니 코드가 더러운 것 같다. 어떻게 하면 좋을까?

다음 게시물에서 yup 라이브러리를 함께 사용하는 법에 대해 알아볼 것이다.

profile
출발선 앞의 준비된 마음가짐, 떨림, 설렘을 가진 신입개발자

0개의 댓글