React hook form으로 폼 구현하기

0
post-thumbnail
post-custom-banner

❓use-hook-form이란

리액트 웹/앱에서 복잡한 폼 로직을 간단하고 효율적으로 관리/구현 할 수 있도록 도와주는 라이브러리이다.


✔️ use-hook-form을 사용했을 때 장점

성능 최적화 : 필요한 컴포넌트만 다시 렌더링되므로, 복잡한 폼에서도 좋은 성능을 제공
간편한 상태 관리 : 폼 데이터를 관리하기 위한 별도의 상태 관리 컴포넌트 및 변수 생성이 필요없다.
유효성 검사 및 에러 처리 : 폼 유효성 검사 및 에러처리를 쉽게 처리할 수 있는 훅(useForm)을 지원한다.
다양한 입력 유형 : 텍스트 입력부터 체크박스, 라디오 버튼, 선택 목록 등 다양한 입력 유형을 지원한다.
생산성 향상 : 무엇보다 register, setValue, handleSubmit 등의 함수를 사용하여 복잡한 폼 로직을 구현할 수 있어 편리하다는 것이 제일 큰 장점이다.

➕ 단점

비제어 컴포넌트: 비제어 컴포넌트를 사용하기 때문에, React의 일관된 상태 관리 패턴을 따르지 않음



❕구현해보기

1️⃣ 설치

npm install react-hook-form
yarn add react-hook-form

2️⃣ form 생성

   <form
      onSubmit={() => console.log("submit")}
    >
      <div className="mt-2">
         <input
            type="text"
          />
          
      </div>

        <button
          type="submit"
        >
          제출
        </button>
      </div>
    </form>

3️⃣ Import 후 useForm 훅으로 함수와 상태 추출하기

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

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

useForm 훅에는 다양한 함수가 존재하지만 내가 프로젝트에서 사용한 함수는 다음과 같다.

  • register
    : 입력 필드 생성 후 필드를 등록한다. 단 각 필드에는 등록 프로세스를 위한 키가 있어야 한다.
{...register("storeType", { required: true })}
  • handleSubmit
    : 폼 유효성 검사를 수행하고 검사가 통과되면 제출 이벤트를 처리한다.
    <form
      onSubmit={handleSubmit(async (data) => {
        const result = await axios.post("/api/comments", {
          ...data,
          storeId,
        });
  • formState :{errors}
    : errors 객체를 통해 해당 필드에 대한 오류 메시지 얻을 수 있다.
{errors?.name?.type === "required" && (
                  <p className="pt-2 text-xs text-red-600">
                    필수 입력사항입니다.
                  </p>
                )}
  • setValue
    : 등록된 필드의 값을 동적으로 설정하고 업데이트할 수 있다. 공식문서에 따르면 불필요한 리렌더링을 방지하도록 설계되어 있다고 한다.
// Update a single field
setValue('name', 'value', {
  shouldValidate: true, // trigger validation
  shouldTouch: true, // update touched fields form state
  shouldDirty: true, // update dirty and dirty fields form state
});
  • resetField
    : 등록된 필드명의 필드 상태과 값을 재설정할 수 있다.
<input {...register("firstName", { required: true })} />
<button type="button" onClick={() => resetField("firstName"))}>Reset</button>

4️⃣ 생성해둔 Form에 적용하기

   <form
      onSubmit={handleSubmit(async (data) => {
        try {
          const result = await axios.post("/api/stores", data);
          if (result.status === 200) {
            toast.success("맛집을 등록했습니다.");
            router.replace(`/stores/${result?.data?.id}`);
          } else {
            toast.error("다시 시도해주세요.");
          }
        } catch (e) {
          toast.error("데이터 생성 중 문제가 발생했습니다. 다시 시도해주세요.");
        }
      })}
    >
      <div className="mt-2">
         <input
            type="text"
            {...register("name", { required: true })}
          />
          {errors?.name?.type === "required" && (
             <p className="pt-2 text-xs text-red-600">
                필수 입력사항입니다.
             </p>
          )}
       </div>

        <button
          type="submit"
        >
          제출
        </button>
      </div>
    </form>

🔗 Form Validation

: register 함수를 통해 정의한 유효성 검사 규칙에 따라 입력 필드의 값이 유효한지 자동으로 검사하며 다음의 규칙을 지원한다.

  • required > boolean
    : 필드의 값을 반드시 입력해야 함을 나타내는 옵션이다.

    <input
      {...register("test", {
        required: true
      })}
    />
  • min > number
    : 필드의 허용되는 최소 값을 나타내는 옵션이다.

    <input
      type="number"
      {...register("test", {
        min: 3
      })}
    />
  • max > number
    : 필드의 허용되는 최대 값을 나타내는 옵션이다.

    <input
      type="number"
      {...register('test', {
        max: 3
      })}
    />
  • minLength > number
    : 필드의 허용되는 값의 최소 길이를 나타내는 옵션이다.

    <input
      {...register("test", {
        minLength: 1
      })}
    />
  • maxLength > number
    : 필드의 허용되는 값의 최대 길이를 나타내는 옵션이다.

    <input
      {...register("test", {
          maxLength: 2
      })}
    />
  • pattern > RegExp
    : 필드의 입력에 대한 정규식 패턴이다.

    <input
      {...register("test", {
        pattern: /[A-Za-z]{3}/
      })}
    />
  • validate > Function | Object
    : Custom Validation 이 필요한 경우 콜백 함수를 인수로 전달하여 유효성을 검사할 수도 있고, 콜백 함수의 개체를 전달하여 모든 유효성을 검사할 수도 있는 옵션이다. 이 함수는 속성에 포함된 다른 유효성 검사 규칙에 의존하지 않고 자체적으로 실행된다.

    <input
      {...register("test", {
        validate: (value, formValues) => value === '1'
      })}
    />
    // object of callback functions
    <input
      {...register("test1", {
        validate: {
          positive: v => parseInt(v) > 0,
          lessThanTen: v => parseInt(v) < 10,
          validateNumber: (_, values) =>
            !!(values.number1 + values.number2), 
          checkUrl: async () => await fetch(),
        }
      })}
    />

💡
참조

post-custom-banner

0개의 댓글