react-hook-form & yup으로 유효성 검사

miin·2022년 7월 16일
0

Library

목록 보기
3/7
post-thumbnail

react-hook-form

Options

register

  • input에서 값을 불러오기 위한 함수로, 다른 옵션을 이용하면 input의 유효성 검사도 쉽게 할 수 있다.
  • <input {...register('사용하고 싶은 이름')}/>
    로 사용하고 사용하고 싶은 변수로 값을 불러올 수 있다. onChange등의 함수를 직접 만들필요가 없다.
  • input에서 입력하는 값을 실시간으로 확인하기 위해 watch라는 함수를 콘솔찍어 사용한다.
  • react-hook-form 에서 import 한 useForm 훅을 사용해서 객체 구조분해 할당으로 register, handleSubmit, watch, errors 등을 꺼낸다.
  • ...register을 쓰는 이유는 name='email',value={email} onChange={onChange}와 똑같기때문
  • register 는 리액트훅폼에게, 이 인풋에 대해 이러한 항목을 입력받을 것이라는 것을 등록해준다.

handleSubmit

  • 리액트훅폼에서 각 항목이 입력되었을 때 submit 이벤트를 처리하는 역할을 한다.

watch

  • register 한 항목의 변경사항을 추적한다

formState

  • errors: 유효성이 통과되지 않으면 에러 상태를 내보내준다.
  • isSubmitting: 중복 제출 방지로 비활성화상태에서 form의 양식이 완료되었을때 활성화 시켜준다

onError

  • handleSubmit은 두가지 인자를 받는데 하나는 onSubmit 정상적으로 submit 되었을때 실행하는 함수이고, 두번째 인자는 onError로 form에서 에러가 났을때 실행되는 함수이다
  • 여기서 에러는 validation을 통과하지 못했다는 것을 의미한다

reset

  • 기존의 데이터를 폼에 뿌려줄때 사용할 수 있음

mode

mode 옵션을 통해 폼 검증이 언제 일어나는지를 정의할 수 있다. 다양한 mode 값들은 폼의 유효성을 검사하는 시점을 조절하여, 사용자 경험을 최적화하고 개발자가 원하는 방식으로 폼 동작을 제어할 수 있게 한다

onSubmit:

  • 목적: 가장 흔하게 사용되며, 폼 제출(submit) 시에 유효성 검사를 수행합니다.

  • 특징: 사용자가 폼을 제출할 때까지 오류 메시지를 표시하지 않아, 폼 입력 과정에서의 사용자 경험이 개선됩니다.
    onChange:

  • 목적: 입력 필드의 값이 변경될 때마다 유효성 검사를 수행합니다.

  • 특징: 사용자가 폼을 작성하는 동안 실시간으로 유효성 검사를 하여, 사용자에게 즉각적인 피드백을 제공합니다.
    onBlur:

  • 목적: 입력 필드가 포커스를 잃었을(focus out or blur) 때 유효성 검사를 수행합니다.

  • 특징: 사용자가 다음 입력 필드로 넘어갈 때마다 유효성 검사를 하여, 너무 많은 실시간 검사로 인한 사용자의 혼란을 줄입니다.
    onTouched:

  • 목적: 필드가 한 번이라도 포커스되었다가 블러(blur) 상태가 됐을 때 유효성 검사를 수행합니다.

  • 특징: 사용자가 필드를 한 번 이상 건드린 후에만 유효성 검사를 하여, 필드에 처음 입력할 때의 압박을 줄입니다.
    all:

  • 목적: 입력의 모든 변화와 블러 상태에 대해 유효성 검사를 즉각적으로 수행합니다.

  • 특징: 가장 엄격한 유효성 검사 모드로, 사용자에게 가장 실시간 피드백을 제공합니다.

예시

import { useForm } from "react-hook-form";
const {register, 
           handleSubmit, 
           watch, 
           formState: {errors, isSubmitting}} = useForm();
 //handleSubmit은 onSubmit을 호출하기 전에 입력 내용을 확인한다
    <form onSubmit={handleSubmit(onSubmit)}>
			<Input
                placeholder="password"
                id="password"
                type="password"
                {...register('password', {
                  //필수요소
                  required: '비밀번호를 입력해주세요.',
                  minLength: {
                    message: '비밀번호는 5글자 이상 입니다.',
                    value: 5,
                  },
                })}
              />
			//minLength에 충족하지 못할때: message
			//값이 비었을때 required
              {errors.password?.message} 
 <button type='submit' disabled={isSubmitting}> Login </button>
   </form>       


참고블로그
https://velog.io/@ckm960411/react-hook-form-TypeScript-%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%9B%85-%ED%8F%BC-%EC%82%AC%EC%9A%A9%EB%B2%95%EA%B3%BC-%ED%83%80%EC%9E%85-%EC%A3%BC%EA%B8%B0

yup

  • 유효성 검사를 해주는 라이브러리
  • required(): 필수
  • min(0), max(0)
  • string() : 문자열로만 사용할 수 있음
  • date() : 날짜형식
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import errMessage from "../../src/commons/validatorError.js";

  const initValue = {
    email: "",
    password: "",
    nick: "",
    phone: "",
  };

  const regexSpacing = /^[^\s]+$/;
  const regexEmailKo = /^[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣]+$/;
  const regexNick = /^[a-z|A-Z|0-9|가-힣]/;
  const regexPasswd =
    /^(?=.*[a-zA-z])(?=.*\d)(?=.*[$`~!@$!%*#^?&\\(\\)\-_=+])(?!.*[^a-zA-z0-9$`~!@$!%*#^?&\\(\\)\-_=+])/;

  const schema = yup.object().shape({
    email: yup
      .string()
      .email(errMessage.email)
      .matches(regexEmailKo, errMessage.email)
      .required(),
    password: yup
      .string()
      .min(5, errMessage.passwdMin(5))
      .matches(regexPasswd, errMessage.passwdRegex) //영문과 숫자, 기호를 최소 1글자씩 포함해주세요
      .matches(regexSpacing, errMessage.passwdSpacing) //비밀번호에는 띄어쓰기를 사용할 수 없어요
      .required(),
    nick: yup
      .string()
      .max(8, errMessage.nickMax(8))
      .matches(regexNick, errMessage.nickRegex)
      .matches(regexSpacing, errMessage.nickSpacing)
      .required(),
    phone: yup.number().required("숫자만 입력할 수 있어요"),
  • 전체코드
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import errMessage from "../../src/commons/validatorError.js";

export default function Join() {
  const initValue = {
    email: "",
    password: "",
    nick: "",
    phone: "",
  };

  const regexSpacing = /^[^\s]+$/;
  const regexEmailKo = /^[^ㄱ-ㅎ|ㅏ-ㅣ|가-힣]+$/;
  const regexNick = /^[a-z|A-Z|0-9|가-힣]/;
  const regexPasswd =
    /^(?=.*[a-zA-z])(?=.*\d)(?=.*[$`~!@$!%*#^?&\\(\\)\-_=+])(?!.*[^a-zA-z0-9$`~!@$!%*#^?&\\(\\)\-_=+])/;

  const schema = yup.object().shape({
    email: yup
      .string()
      .email(errMessage.email)
      .matches(regexEmailKo, errMessage.email)
      .required(),
    password: yup
      .string()
      .min(5, errMessage.passwdMin(5))
      .matches(regexPasswd, errMessage.passwdRegex) //영문과 숫자, 기호를 최소 1글자씩 포함해주세요
      .matches(regexSpacing, errMessage.passwdSpacing) //비밀번호에는 띄어쓰기를 사용할 수 없어요
      .required(),
    nick: yup
      .string()
      .max(8, errMessage.nickMax(8))
      .matches(regexNick, errMessage.nickRegex)
      .matches(regexSpacing, errMessage.nickSpacing)
      .required(),
    phone: yup.number().required("숫자만 입력할 수 있어요"),
  });

  const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm({
    mode: "onChange",
    resolver: yupResolver(schema),
  });

  const handleJoin = async (data) => {
    const reqData = {
      email: data.email,
      password: data.password,
      nick: data.nick,
      phone: data.phone,
    };

     const result = await httpRequest("POST", `/login/v2`, reqData);

     if (result.success) {
       console.log("회원가입 성공!");
       route.replace("/room");
     } else if (result.status === 409) {
       alert("이미 가입되어 있는 회원입니다.");
     }
  };

  return (
    <>
      <form
        onSubmit={handleSubmit(handleJoin)}
        style={{ display: "flex", flexDirection: "column" }}
      >
        <label>
          email:
          <input
            name="email"
            initValue={initValue.email}
            {...register("email")}
          />
          <p className="loginNotice">{errors.email?.message}</p>
          <button type="button">중복확인</button>
          <button type="button">발송</button>
        </label>
        <label>
          PW:
          <input
            type="password"
            name="password"
            initValue={initValue.password}
            {...register("password")}
          />
          <div className="loginNotice">{errors.password?.message}</div>
        </label>
        <label>
          Nick Name:
          <input
            name="nick"
            initValue={initValue.nick}
            {...register("nick")}
          />
          <p className="loginNotice">{errors.nick?.message}</p>
          <button type="button">중복확인</button>
        </label>
        <label>
          Phone Number:
          <input
            name="phone"
            initValue={initValue.phone}
            {...register("phone")}
          />
          <p className="loginNotice">{errors.phone?.message}</p>
          <button type="button">인증</button>
        </label>
        <button className="joinButton">Join</button>
      </form>
    </>
  );
}

https://rossbulat.medium.com/introduction-to-yup-object-validation-in-react-9863af93dc0e

0개의 댓글