개발

yup - 유효성 검사 라이브러리

썽연 2022. 6. 27. 12:45
728x90

formik를 공부해보면서 yup 라이브러리를 설치해서 유효성을 검사하길래 찾아보았다.

yup가 무엇일까?

yup은 유효성 검사를 보다 쉽게 도와주는 라이브러리이다.

설치해보자!

yarn add yup

yup은 다양한 기능을 제공한다.

최소 길이, 최대 길이, 필수 여부에 따라 그에 맞도록 에러메시지를 뱉을 수 있다.

email: Yup.string()
    .matches(/^[^@\s]+@[^@\s]+\.[^@\s]+$/, '이메일 형식에 맞지 않습니다.')
    .required('이메일을 입력해주세요.'),

여기서 email을 할 때 주의할 점이 있다.

email의 조건을 줄 때 주의할 점 !
yup은 email 조건을 .email로 표현할 수 있다
하지만, yup의 email을 사용한다면 한국에서와 외국에서의 이메일 조건이 다르기 때문에
.으로 시작하는 이메일이 되지 않는다. (하지만 네이버에서는 .으로 시작하는 이메일이 만들어진다)
그러므로 email을 쓰는 것 대신 matches로 정규식을 사용하자!

유효성 검사 정규식을 넣고싶다면?

eamil:Yup.string()
    .matches(/정규식/, '조건에만족하지않을때 에러메시지')

위와 같이 matches를 이용해서 정규식을 넣어주자!

나는 yup을 이용해서 회원가입 유효성검사를 하려고 했다.

이메일, 비밀번호, 비밀번호 확인, 이름, 폰번호, 인증코드의 input이 필요하였다.

하지만, 여기서 비밀번호 확인이 비밀번호의 정규식과 일치하고, 비밀번호와 같아야하는데 이것을 어떻게해야하나 🤔 싶었다.

matches의 첫번째 인자는 무조건 정규식이어야한다!

그래서 나는 password라는 함수를 받으려고 했다.

import * as Yup from 'yup';

export const createSignUpValidationSchema = (password: string) => {
  Yup.object({
    email: Yup.string()
      .matches(/^[^@\s]+@[^@\s]+\.[^@\s]+$/, '이메일 형식에 맞지 않습니다.')
      .required('이메일을 입력해주세요.'),
    password: Yup.string()
      .matches(
        /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,10}$/,
        '6~10자의 영문, 숫자를 조합해서 입력하세요.',
      )
      .min(6, '6글자 이상 10글자 이하로 입력해주세요.')
      .max(10, '6글자 이상 10글자 이하로 입력해주세요.')
      .required('비밀번호를 입력해주세요.'),
    passwordConfirm: Yup.string()
      **.matches(new RegExp(`^${password}$`), '비밀번호가 다릅니다')**
      .oneOf([Yup.ref('password'), null], '비밀번호가 다릅니다.')
      .required('비밀번호를 한번 더 입력해주세요.'),
    phone: Yup.string()
      .matches(/^[0-9]{11}$/i, '번호는 01012345678형태로 입력해주세요')
      .required('휴대폰 번호를 입력해주세요'),
    name: Yup.string()
      .matches(/^[가-힣]{2,5}$/, '한글로 입력해주세요.')
      .min(2, '2글자 이상 5글자 이하로 입력해주세요')
      .max(4, '2글자 이상 5글자 이하로 입력해주세요')
      .required('이름을 입력해주세요.'),
    code: Yup.string().length(6, '코드의 길이가 다릅니다.').required('인증코드를 입력해주세요.'),
    privacy: Yup.boolean().oneOf([true], '회원가입을 위해 약관에 동의해주세요.'),
  });
};
.matches(new RegExp(`^${password}$`), '비밀번호가 다릅니다')

위와 같이 passwordConfirm에 인자를 받으려고 하였으나,

useFormik를 사용하는 곳에서 validation=createSignUpValidationSchema(password)

를 받으려고 했으나, useFormik가 끝나지 않는 곳에서 value를 받기 때문에 어떻게 해야하나 싶었다.

그래서 이것은 패스하고 다른방법을 찾아보았다.

validationSchema를 주기 위해선 useFormik 대신,

Field Array를 사용하고 있었던 것이다.

import React from 'react';
import { Formik, Form, Field } from 'formik';
import * as Yup from 'yup';

**const DisplayingErrorMessagesSchema = Yup.object().shape({
  username: Yup.string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required('Required'),
  email: Yup.string().email('Invalid email').required('Required'),
});**

export const DisplayingErrorMessagesExample = () => (
  <div>
    <h1>Displaying Error Messages</h1>
    <Formik
      initialValues={{
        username: '',
        email: '',
      }}
      **validationSchema={DisplayingErrorMessagesSchema}**
      onSubmit={values => {
        // same shape as initial values
        console.log(values);
      }}
    >
      {({ errors, touched }) => (
        <Form>
          <Field name="username" />
          {/* If this field has been touched, and it contains an error, display it
           */}
          {touched.username && errors.username && <div>{errors.username}</div>}
          <Field name="email" />
          {/* If this field has been touched, and it contains an error, display
          it */}
          {touched.email && errors.email && <div>{errors.email}</div>}
          <button type="submit">Submit</button>
        </Form>
      )}
    </Formik>
  </div>
);

하지만 나는 useFormik를 사용하고 있기에 다른 방법을 찾아봤다.

알고보니 yup은 생각보다 대단한 라이브러리였다!

비밀번호 확인과 같이, 앞서 지정해준 비밀번호와 똑같은지 검사를 할 수 있었다.

passwordConfirm: Yup.string()
    .oneOf([Yup.ref('password'), null], '비밀번호가 다릅니다.')

**oneOf(values : array, message)**로 사용할 수 있었다.

oneOf는 즉, 뒤에 있는 배열에 맞는 값을 true로 반환한다!

let schema = yup.mixed().oneOf(['jimmy', 42]);

await schema.isValid(42); // => true
await schema.isValid('jimmy'); // => true
await schema.isValid(new Date()); // => false

위 코드를 보면 oneOf가 무엇을 뜻하는지 쉽게 이해할 수 있을 것 같다.

그럼 ref가 무엇인지 찾아보았다.

ref(path: string, options: { contextPrefix: string }): Ref

위와 같이 사용할 수 있었다.

ref란 형제 자매 또는 그 다른 자손 필드를 참조하여 만든다!

즉, 비밀번호 확인 코드를 해석해보자.

**.oneOf([Yup.ref('password'), null], '비밀번호가 다릅니다.')**

password라는 형제를 만들어서, 그 같은 값과 null이 아니라면 비밀번호가 다르다고 오류를 내뱉는단 소리!

yup을 이용하여 회원가입 최종 코드는 다음과 같다.

import * as Yup from 'yup';

export const SignUpValidationSchema = Yup.object({
  email: Yup.string()
    .matches(/^[^@\s]+@[^@\s]+\.[^@\s]+$/, '이메일 형식에 맞지 않습니다.')
    .required('이메일을 입력해주세요.'),
  password: Yup.string()
    .matches(
      /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,10}$/,
      '6~10자의 영문, 숫자를 조합해서 입력하세요.',
    )
    .min(6, '6글자 이상 10글자 이하로 입력해주세요.')
    .max(10, '6글자 이상 10글자 이하로 입력해주세요.')
    .required('비밀번호를 입력해주세요.'),
  passwordConfirm: Yup.string()
    .oneOf([Yup.ref('password'), null], '비밀번호가 다릅니다.')
    .required('비밀번호를 한번 더 입력해주세요.'),
  phone: Yup.string()
    .matches(/^[0-9]{11}$/i, '번호는 01012345678형태로 입력해주세요')
    .required('휴대폰 번호를 입력해주세요'),
  name: Yup.string()
    .matches(/^[가-힣]{2,5}$/, '한글로 입력해주세요.')
    .min(2, '2글자 이상 5글자 이하로 입력해주세요')
    .max(4, '2글자 이상 5글자 이하로 입력해주세요')
    .required('이름을 입력해주세요.'),
  code: Yup.string().length(6, '코드의 길이가 다릅니다.').required('인증코드를 입력해주세요.'),
  privacy: Yup.boolean().oneOf([true], '회원가입을 위해 약관에 동의해주세요.'),
});

현재, privacy의 여부를 주는 방법을 모르므로 공부해봐야겠다.

import 할 때 *을 주면 as 를 써 주어야 하는 것을 명심하자! ⇒ 처음에 안해서 에러가 났다 ..

yup을 공부하면서 느낀점은

라이브러리를 많이 이용하고, 공식문서에 검색하는 습관을 길러야겠다.

영어공부를 더 열심히해야겠다.. ! 📝

728x90