seunghyun Note

React-hook-form 본문

스터디/REACT

React-hook-form

승숭슝현 2024. 3. 12. 20:05

기존에 사용했던 제어 컴포넌트들의 반복되는 코드들과 유효성 검증을 한다면 코드가 점점 길어질 것이다.
react에서 컴포넌트 리랜더링이 발생하는 조건 중 하나는 state가 변했을 때이다.
폼에서는 모든 값이 state로 연결되어 있으면 하나의 값이 변할 때 마다 여러개의 자식 컴포넌트들에서 무수히 많은 리랜더링이 발생한다. (즉 불필요한 렌더링이 반복된다)

react-hook-form

install

npm i react-hook-form

useForm() 을 사용해서 회원가입 form 만들기

  const { register, watch } = useForm();

 

useForm() 안에는 여러가지 옵션들이 있다.

  • register : register function은 많은 요청들을 해결해주고 handler 를 대신해준다.
const { onChange, onBlur, name, ref } = register('firstName');
// include type check against field path with the name you have supplied.

<input
  onChange={onChange}// assign onChange event
  onBlur={onBlur}// assign onBlur event
  name={name}// assign name prop
  ref={ref}// assign ref prop
/>
// same as above
<input {...register('firstName')} />

 

  • watch : watch는 form 의 입력값들의 변화를 관찰 할 수 있게 해주는 함수이다.
function ToDoList() {
  const { register, watch } = useForm();
  console.log(watch());
  return (
    <div>
      <form>
        <input {...register("email")} placeholder="Email" />
        <input {...register("firstName")} placeholder="First Name" />
        <input {...register("lastName")} placeholder="Last Name" />
        <input {...register("username")} placeholder="Username" />
        <input {...register("password")} placeholder="Password" />
        <input {...register("password1")} placeholder="Password1" />
      </form>
    </div>
  );
}
export default ToDoList;

input에 데이터를 넣으면 아래와 같이 된다.

email: 'cvtcvt007@naver.com', 
firstName: 'kim', 
lastName: 'seunghyun',
 username: 'ashel', 
password: '1234', …}
email
: 
"cvtcvt007@naver.com"
firstName
: 
"kim"
lastName
: 
"seunghyun"
password
: 
"1234"
password1
: 
"1234"
username
: 
"ashel"

기존 form에서는 event.preventDefault()를 이용해 form의 제출을 사용했다.
useForm()에서는 handleSubmit을 사용한다.

  const { register, watch, handleSubmit } = useForm();

handleSubmit을 통해 출력해보자

function ToDoList() {
  //handleSubmit은 form에서 사용된다.
  const { register, handleSubmit } = useForm();

  //button을 클릭 후 제출 시 onValid 함수가 출력된다.
  const onValid = (data: any) => console.log(data);

  return (
    <div>
    //require만 추가해주면 유효성검사가 된다. 
      <form onSubmit={handleSubmit(onValid)}>
 <input {...register("email", { required: true })} placeholder="Email" />
        <input
          {...register("firstName", { required: true })}
          placeholder="First Name"
        />
        <input
          {...register("lastName", { required: true })}
          placeholder="Last Name"
        />
        <input
          {...register("username", { required: true, minLength: 10 })}
          placeholder="Username"
        />
        <input
          {...register("password", { required: true, minLength: 5 })}
          placeholder="Password"
        />
        <input
          {...register("password1", {
            required: "Password is required",
            minLength: {
              value: 5,
              message: "Your password is too short.",
            },
          })}
          placeholder="Password1"
        />
        <button>Add</button>
      </form>
    </div>
  );
}
export default ToDoList;

 

  • formState : 전체 양식 상태에 대한 정보가 포함되어 있다. 다양한 옵션들이 있지만 결국 error를 찾기에 적합하다.
import { useState } from "react";
import { useForm } from "react-hook-form";

function ToDoList() {
  //formState를 통해 valid되지 않은 데이터들을 출력한다. 
  const { register, handleSubmit, formState } = useForm();
  const onValid = (data: any) => {
    console.log(data);
  };
  console.log(formState.errors);
  return (
    <div>
      <form
        style={{ display: "flex", flexDirection: "column" }}
        onSubmit={handleSubmit(onValid)}
      >
        <input {...register("email", { required: true })} placeholder="Email" />
        <input
          {...register("firstName", { required: true })}
          placeholder="First Name"
        />
        <input
          {...register("lastName", { required: true })}
          placeholder="Last Name"
        />
        <input
          {...register("username", { required: true, minLength: 10 })}
          placeholder="Username"
        />
        <input
          {...register("password", { required: true, minLength: 5 })}
          placeholder="Password"
        />
        <input
          {...register("password1", {
            required: "Password is required",
            minLength: {
              value: 5,
              message: "Your password is too short.",
            },
          })}
          placeholder="Password1"
        />
        <button>Add</button>
      </form>
    </div>
  );
}
export default ToDoList;

여기까지는 formState를 통해 검사했을 때 error를 콘솔에 출력했다.
email 같은 특정 정규식의 valid를 찾기 위해서는 정규식을 사용한다.
결국 검사는 pattern, required를 통해 한다.

  • 정규식 사용
<input
          {...register("email", {
            required: "Email is required",
            //pattern 내에 value : 정규식을 추가해주고 , message를 통해 틀렸을 때의 출력을 해준다.
            pattern: {
              value: /^[A-Za-z0-9._%+-]+@naver.com$/,
              message: "Only naver.com emails allowed",
            },
          })}
          placeholder="Email"
        />

이제 사용자 화면에도 틀린 유효성 검사를 출력하자.

기존에 있던 formState.errors를 삭제하고 formState:{errors}를 저장하자.

 const {
    register,
    handleSubmit,
    formState: { errors },
   //생성된 inteface를 넣어준다.
  } = useForm<IForm>({
    defaultValues: {
      email: "@naver.com",
    },
  });

interface를 생성

interface IForm {
  email: string;
  firstName: string;
  lastName: string;
  username: string;
  password: string;
  password1: string;
}

span 태그 내에 error를 출력한다.

//다른 항목의 유효성검사도 같은 코드이다. 
<span>{errors?.email?.message}</span>

 

  • setError : 특정한 error를 발생시켜준다.
 const onValid = (data: IForm) => {
    if (data.password !== data.password1) {
      //useForm에 있는 setError를 이용한다.
      setError(
        //password1 은 기존에 register로 저장된 값이다. password로 바꾸면 위에 출력된다.
        "password1",
        {
          //나중에 Error.message를 통해 출력될 값을 넣어준다. 
          message: "Password are not the same",
        },
        { shouldFocus: true }
      );
    }
  };

 

  • shouldFocus : shouldFocus를 통해 틀렸을 때 이동시킨다.
 const onValid = (data: IForm) => {
    if (data.password !== data.password1) {
      setError(
        "password1",
        { message: "Password are not the same" },
        //shouldFocus를 통해 틀리면 이동시킨다. 
        { shouldFocus: true }
      );
    }

  };

 

  • validate : 특정 이름이나 단어들을 원하지 않을 때 (또는 포함이 됐을 때 ) 허용시키지 않는다.

회원가입을 할 때 특정 단어나 욕설, 비방 단어들을 관리할 때 사용한다. (게임에서 아이디를 만들 때 "사용할 수 없습니다")

       <input
          {...register("firstName", {
            required: "write here",
            validate: {
              noPizza: (value) =>
                value.includes("pizza") ? "no pizza allowed" : true,
              noAdmin: (value) =>
                value.includes("admin") ? "no admin allowed" : true,
            },
          })}
          placeholder="First Name"
        />
728x90

'스터디 > REACT' 카테고리의 다른 글

Recoil & react-hook-from (✈️ travel list)  (2) 2024.03.13
Recoil  (0) 2024.03.11
React 데이터 관리 및 라우팅  (1) 2024.02.24