[React] react hook form

bunny.log·2022년 6월 5일
0

react hook form

React에서 formvalidation을 도와주는 라이브러리이다.

이 라이브러리는 기본적으로 uncontrolled component를 베이스로 하지만 controlled component에 대한 지원도 하고 있다.

react hook form의 장점

  • 가볍다.
  • 다른 디펜던시가 없다.
  • ref를 기반으로 하여 다른 UI 라이브러리와 호환이 잘된다.
  • 기존의 폼에서 입력해야하는 여러가지 번거로운 작업을 줄여준다 (value 설정, 데이터 전송 관리 등등)
  • 다른 라이브러리와 다르게 폼을 위한 컴포넌트나, 필드를 위한 컴포넌트가 없다.
  • 빠른 마운팅
  • 적은 코드로 더 좋은 퍼포먼스를 낼 수 있다.
  • 다른 라이브러리 혹은 React에 비해 Re-render 수가 적다.
  • Fast Mounting (로딩속도가 빠름)
  • TS를 기본으로 지원

react-hook-form 설치하기

npm i react-hook-form

기존 form 사용법

// Login.js - React 내부의 간단한 로그인 폼

// 웹페이지 상태(state)관리를 위한 useState hook 불러오기
import { useState } from "react";

const Login = () => {
  // 아이디와 비밀번호 state로 관리하기
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  
  // input 태그에서 아이디와 비밀번호 받아와, state 변경해주기
  const onValidName = (event) => {
    setUsername(event.target.value)
  }
  const onValidPassword = (event) => {
    setUsername(event.target.value)
  }
  
  // 로그인 버튼 눌렀을때, 아이디와 비밀번호 state값 가져오기
  const handleSubmit = (event) => {
    event.preventDefault();
    console.log(username, password);
  }
  
  //input 값이 바뀔때마다 state값, value값 최신화
  return (
    <form onSubmit={handleSubmit}>
      <Input
        value={username}
        type="text"
        placeholder="아이디"
        onChange={onValidName}
      />
      <Input
        value={password}
        type="password"
        placeholder="비밀번호"
        onChange={onValidPassword}
      />
      <Input type="submit" value="로그인" />
   </form>
  );
};

export default Login;

react-hook-form 사용법

const { register, handleSubmit } = useForm();

React-Hook-Form 은 데이터 검증을 보다 간단하게 하는 등의, input 값 관리를 쉽게 해주는 register 를 지원한다. register는 해당 컴포넌트의 값을 트래킹하고 validation을 하기위해 react hook form 라이브러리에 등록한다는 뜻이다.

input을 등록하려면 아래처럼 refregister을 넘겨주면 된다. 이 때 중요한 점은 반드시 name 필드를 넘겨줘야 하며, 이는 유니크해야된다는 것이다.

<input type="text" ref={register} name="firstName" />

handleSubmit 메서드는 form 제출을 핸들링하는 메서드이며, form 컴포넌트onSubmit prop에 넘겨주면 된다.

const onFormSubmit = data => console.log(data);
const onErrors = errors => console.error(errors);
 
<form onSubmit={handleSubmit(onFormSubmit, onErrors)}>
    {/* ... */}
</form>

handleSubmit은 두가지 아규먼트를 받는다.
첫번째는 폼 validation이 success일 때 호출하는 콜백이고
두번째는 폼 validation이 fail일 때 에러와 함께 호출되는 콜백이다.

간단한 example은 아래와 같다.

import React from "react";
import { useForm } from "react-hook-form";
 
export default function App() {
  const { register, handleSubmit } = useForm();
  const onSubmit = data => console.log(data);
 
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstName" ref={register} />
      <input name="LastName" ref={register} />            
      <input type="submit" />
    </form>
  );
}

handleSubmit() 사용, onSumit 함수에 post요청 > json 변환.

watch

input에서 입력하는 값을 실시간으로 확인하기 위해서는 watch라는 함수를 사용할 수 있습니다.

export default function App() {
  const { register, watch } = useForm();
  console.log(watch());
  return (
    <div className="App">
      <form>
        <input type="text" placeholder="username" {...register("username")} />
        <input type="submit" />
      </form>
    </div>
  );
}

위의 코드를 보면 알겠지만, 기본적으로 ref를 사용하는 uncontrolled 방식이기 때문에 onChangevalue 같은 상태 값을 prop으로 넘겨줄 필요가 없어 코드가 깔끔하다.

다른 코딩 예시

<input
          type="text"
          placeholder="username"
          {...register("username", {
            required: "Username is required",
            minLength: {
              value: 5,
              message: "Username must be longer than 5 characters"
            }
          })}
        />

Validation과 Error 다루기

여기서 에러는 Validation을 통과하지 못했다는 것을 의미합니다

validation 옵션은 register 메서드에 아규먼트로 넣어주면 된다.
validation option은 아래와 같다.

  • required
  • minLength, maxLength (문자열 길이)
  • min, max (숫자)
  • type (input 필드의 타입. email, number, text 등)
  • pattern (regex)

input의 required 는 필수 값 체크를 해주고, minLength 는 입력 값의 최소 길이 체크를 해준다.

<Input name="name" innerRef={register({ required: true })} />

위의 코드는 input 컴포넌트를 required하게 한 것인데 만약 아무 값도 입력하지 않고 서브밋하면 handleSubmit 메서드의 두번째 콜백이 실행된다.

<Input name="name" innerRef={register({ 
		pattern : {
           value : /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
           errors : "이메일 형식에 맞게 입력해주세요
         }
       }) />

그리고 에러 오브젝트는 useForm에서 접근할 수 있다.

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

실시간 유효성 검사

실시간 유효성 검사를 사용하기 위해서는 useForm을 다음과 같이 변경하여야 합니다.

useForm({ mode: "onChange" });

errors는 에러들이 담긴 객체로 현재는 모드가 onChange이기 때문에 에러가 실시간으로 업데이트 됩니다.

userForm을 다음과 같이 변경하게 되면 React Hook Form이 실시간으로 유효성 검사를 하게 됩니다. 먼저 input에 Validation을 설정한 다음에 useForm에서 errors라는 객체를 가져옵니다.

import React from "react";
import { useForm } from "react-hook-form";
import "./styles.css";

export default function App() {
  const { register, handleSubmit, errors } = useForm();
  const onSubmit = (data) => {
    console.log(data);
  };
  const onError = (error) => {
    console.log(error);
  };
  return (
    <div className="App">
      <form onSubmit={handleSubmit(onSubmit, onError)}>
        <input
          type="text"
          placeholder="username"
          {...register("username", {
            minLength: {
              value: 5,
              message: "Username must be longer than 5 characters"
            }
          })}
        />
        <input type="submit" />
      </form>
      {erros && <h1>{error?.username?.message}</h1>}
    </div>
  );
}

다음과 같이 코드를 짜면 유효성 검사를 통과하지 못할때마다 에러 메세지가 나타난다.

Typescript 적용 예

// react-hook-form에서 폼 만들기 위한 useForm, 폼의 전송함수를 관리하기 위한 SubmitHandler 가져오기
import { useForm, SubmitHandler } from "react-hook-form"

// 폼에 들어갈 데이터 형식 지정하기
type myForm {
  name: string,
  lastName?: string
}

// react App 내부에서, useForm을 사용해 폼을 만들기위한 여러가지 요소 불러오기
function App() {
  // 폼을 만들기 위한 여러가지 요소 불러오기, 폼 타입 지정해주기
  const { register, handleSubmit, getValues } = useForm<myForm>();
  
  // SubmitHandler로 타입 지정해주기 ( data를 사용할 경우에만 지정 )
  const onValid:SubmitHandler<myForm> = (data) => {
    console.log(data)
    
    // getValues만 사용한다면, 이미 타입이 지정되어있으므로 따로 지정해 줄 필요가 없음
    const { name, firstName } = getValues();
  }
  
  return {
    <div>
      <form onSubmit={handleSubmit(onValid)}>
        <input {...register("name")}/>
        <input {...register("firstName", { required : true })/>
      </form>
    </div>
  }

서드 파티 컴포넌트와 함께 쓰기

material ui 처럼 반드시 controlled component 형태로 사용하는 라이브러리들이 있는데, react hook form은 이런 컴포넌트를 지원한다. 이 경우에는 register 메서드 대신 control 이라는 객체를 사용한다.

const { register, handleSubmit, errors, control } = useForm();

또한 react hook form에서는 Controller 라는 wrapper 컴포넌트를 제공한다. 이 컴포넌트를 통해서 controlled component를 래핑해서 react hook form과 사용할 수 있다.

아래의 예시에서 보면 register을 넘겨주듯이 대신 control을 넘겨주고, as prop으로 사용하고자 하는 controlled component를 내려준다. 그리고 그 컴포넌트의 props는 그대로 Controller에서 전달 가능하다. validation option은 rules prop으로 넘겨주면 된다.

<Controller
  name="role"
  control={control}
  as={Select}
  options={selectOptions}
  defaultValue=""
  rules={{ required: "Role is required" }}
/>

추천 링크
https://velog.io/@pluviabc1/React-Hook-Form-%EB%B2%A0%EC%9D%B4%EC%A7%81

Ref
https://blog.logrocket.com/the-complete-guide-to-react-hook-form/
https://react-hook-form.com/kr/get-started

출처
https://developer-alle.tistory.com/421

profile
나를 위한 경험기록

0개의 댓글