React

react-hook-form 리액트 유효성 검사

함형우 2023. 7. 6. 13:53
728x90

작업중인 웹페이지에 회원가입 탭이다. 내 쿼리에 들어갈 정보들 중, 자동입력되는 값들을 제외하고 모두 입력받는 폼이다. 우리는 이 정보들이 제대로 들어오게, 쿼리에서 오류를 반환하지 않도록 해야하는 의무가 있다.

그러기위해 보통 유효성검사를 사용한다. 서버쪽 코드에서도 사용할 수 있지만, 보통 클라이언트단에서 처리하기 때문에, 우리는 리액트에서 유효성 검사를 어떻게 하는지 알아보자

React Hook Form

React Hook Form은 React 기반의 라이브러리로, 유효성 검사, 폼 제출을 쉽게 처리할 수 있도록 도와주는 라이브러리다. 직관적인 api가 제공되고, 비슷한 기능을 제공하는 Formik 보다 안정적인 성능을 지원한다.

  • Hook 기반으로 폼 상태와 동작을 관리, 'useForm' 을 사용해 인스턴스를 생성 - 다양한 훅을 사용
  • Form-uncontrolled 컴포넌트를 사용하여 form 값 추적, ref를 사용해 필드를 연결, 추적, 검사 작업 수행
  • HandleSubmit 함수를 사용하여 폼의 제출 처리, 제출 이벤트를 핸들링 가능
React Hook Form 설치
npm install react-hook-form

react-hook-form 라이브러리를 설치

React Hook Form 적용

라이브러리를 사용할 form이 존재하는 페이지에 해당 라이브러를 import 해준다.

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

그 후, useForm에 존재하는 hook을 호출해야한다. 메인 컴포넌트 함수 내에서 아래와 같은 useForm 훅을 호출하자

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

const onSubmit = (data) => {
  console.log(data); // 폼 데이터를 처리하는 로직을 작성합니다.
};

폼을 제출하는 이벤트가 발생할 경우, 실행될 핸들러 함수 실제로 데이터를 처리하는 로직은 이곳에 작성해야한다. 지금은 서비스 로직을 따로 구현하지 않기때문에 유효성체크가 되지 않으면 알람이 뜨는 정도만 진행한다.

<form onSubmit={handleSubmit(onSubmit)}>
  <input
    type="text"
    name="username"
    placeholder="사용자 이름"
    {...register("username", { required: true })}
  />
  {errors.username && <span>사용자 이름은 필수입니다.</span>}
  {/* ... */}
  <button type="submit">제출</button>
</form>

폼을 제출하기 위한 form을 선언하고, onSubmit (위에서 선언한 핸들러 함수)를 handleSubmit(onSubmit)을 사용하여 태그에 추가하자

그 후 중요한건 name="" 과 {...register에 등록될 프로퍼티의 이름이 동일해야 한다. 해당 프로퍼티 값을 통해 유효성을 체크한다.

            <Form.Control
                type="text"
                placeholder="이메일"
                name="email"
                {...register("email", {
                    required: true,
                    pattern: /^\S+@\S+$/i
                })}
            />

이처럼 정규식을 사용하거나, 유효성 검사 규칙을 설정할 수 있기때문에 기본적인 사항은 모두 적용 가능하다.

register("name", {required: true, minLength: 10});
register("name", {required: "해당 필드는 필수입니다.", minLength: {
  value: 3,
  message: "3글자 이상 입력해주세요."
}
});

위와 같은 사양도 가능하다. 생각보다 바리에이션이 많으니 공식문서를 참고하는게 좋다.

https://react-hook-form.com/

 

React Hook Form - performant, flexible and extensible form library

Performant, flexible and extensible forms with easy-to-use validation.

react-hook-form.com

register 함수에는 프로퍼티 값이 들어간다, 에러 정보를 입력하는건 errors 함수에 들어간다. errors는 formState에 객체에 존재한다. 해당 객체에 { id : { type: ..., message: ..., ... } 로 저장된다. formState는 단어 그대로 해당 폼에 정보에 대한 값들이 들어있다.

submit 된 숫자, 혹은 수정된 필드들이 담겨있는 dirtyFields, 에러가 있는지 알 수 있는 isValid 등등이 존재한다.

watch / getValues

위 함수는 둘다 값을 추적하는 함수로, 비밀번호 확인이나 동일값을 비교할때 자주 사용된다. 

	<Form.Control
              type="password"
              placeholder="비밀번호"
              name="password"
              {...register("password", {
                  required: true,
                  minLength: 6
              })}
            />
              {errors.password && errors.password.type === "required" && (
                <ErrorMessage>비밀번호는 필수 입력 항목입니다.</ErrorMessage>
              )}
              {errors.password && errors.password.type === "minLength" && (
                <ErrorMessage>비밀번호는 최소 6자 이상이어야 합니다.</ErrorMessage>
              )}
            <Form.Control
              type="password"
              placeholder="비밀번호 확인"
              name="confirmPassword"
              {...register("confirmPassword", {
                  required: true,
                  validate: (value) =>
                  value === getValues("password") || "비밀번호가 일치하지 않습니다."
              })}
            />
              {errors.confirmPassword && errors.confirmPassword.type === "required" && (
                <ErrorMessage>비밀번호 확인은 필수 입력항목입니다.</ErrorMessage>
              )}
              {errors.confirmPassword && errors.confirmPassword.type === "validate" && (
                <ErrorMessage>{errors.confirmPassword.message}</ErrorMessage>
              )}

watch("name값")

비제어 컴포넌트로 폼을 구현할 때에 조건에 따라, 다르게 필드를 노출해야 하는 상황이 존재한다. 이런 상황에서 watch 함수는 폼에 입력된 값을 구독하여 실시간으로 체크할 수 있다. 매개변수를 주지 않으면 전체 값, 매개변수를 받는다면 해당 값만 관찰한다. 

getValues("name값")

두개의 또렷한 차이점은 getValues같은 경우는 컴포넌트의 리렌더링을 일으키지 않는다. 입력값의 변화를 구독하지 않는다는 점도 존재한다.


 

728x90