React Form Validation 폼태그 유효성 검증을 쉽게 도와주는 Formik 사용방법

leehyunju·2021년 5월 22일
19
post-thumbnail

안녕하세요 오늘은 리액트에서 폼태그 유효성 검증을 쉽게 도와주는 Formik에 대해 깊이 다뤄보는 방법을 공유해 보겠습니다.

const Form = () => {
  const intialValues = { email: "", password: "" };
  const [formValues, setFormValues] = useState(intialValues);
  const [formErrors, setFormErrors] = useState({});
  const [isSubmitting, setIsSubmitting] = useState(false);
}

사용시 useState hook을 사용하여 formValues, formErrors, isSubmitting에 대한 상태 변수를 설정합니다.

  • formValues 변수는 사용자가 입력 필드에 입력 한 데이터를 보유합니다.
  • formErrors 변수는 각 입력 필드에 대한 오류를 보유합니다.
  • isSubmitting 변수는 양식이 제출 중인지 여부를 추적하는 논리형(boolean) 입니다. 이는 양식에 오류가 없는 경우에만 해당됩니다.
const submitForm = () => {
    console.log(formValues);
  };

 const handleChange = (e) => {
    const { name, value } = e.target;
    setFormValues({ ...formValues, [name]: value });
  };

const handleSubmit = (e) => {
    e.preventDefault();
    setFormErrors(validate(formValues));
    setIsSubmitting(true);
  };

const validate = (values) => {
    let errors = {};
    
    //정규식 표현
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i;
    
    //이메일 값이 없을시
    if (!values.email) {
      errors.email = "Cannot be blank";
      //이메일 정규식 표현이 옳지 않을시
    } else if (!regex.test(values.email)) {
      errors.email = "Invalid email format";
    }
    
    //비밀번호 값이 없을시
    if (!values.password) {
      errors.password = "Cannot be blank";
      //비밀번호의 길이(length)가 4글자 이하일 때
    } else if (values.password.length < 4) {
      errors.password = "Password must be more than 4 characters";
    }
    
    //에러를 반환해줘 !
    return errors;
  };

// 폼태그에 값이 0 이거나, isSubmitting 이 false 상태일 때,
//submitForm을 누르면 [formErrors]가 마운트 되도록!
useEffect(() => {
    if (Object.keys(formErrors).length === 0 && isSubmitting) {
      submitForm();
    }
  }, [formErrors]);

이 코드에는 4개의 양식 핸들러와 양식의 기능을 처리하기 위해 설정된 useEffect가 있습니다.

  • handleChange : 입력이 formValues상태와 동기화 된 상태로 유지되고 사용자가 입력 할 때 상태가 업데이트됩니다.

  • validate : formValues 객체를 이 함수에 대한 인수로 전달한 다음 이메일과 이름, 비밀번호를 유효성 검사 테스트 하면서 오류가 채워지고 반환됩니다.

  • handleSubmit : 양식이 제출 될 때마다 formErrors 상태 변수는 setFormErrors (validate (formValues)) 메소드를 사용하여 오류를 나타냅니다.

  • useEffect : formErrors 객체가 비어 있는지, isSubmitting이 참인지 확인합니다. 이 검사가 참이면 submitForm()이 호출됩니다. 단일 종속성, 즉 formErrors 객체도 있는데 formErrors 객체가 변경 될 때만 실행됩니다.

  • submitForm : 폼 데이터의 제출을 처리합니다.

return (
    <div className="container">
      <h1>Sign in to continue</h1>
      
      {Object.keys(formErrors).length === 0 && isSubmitting && (
        <span className="success-msg">Signed in successfully</span>
      )}
      
      // 버튼을 누르면 이 폼에 데이터들이 제출되도록 handleSubmit
      <form onSubmit={handleSubmit} noValidate>
        
        //이메일 검사
        <div className="form-row">
          <label htmlFor="email">Email</label>
          <input
            type="email"
            name="email"
            id="email"
            value={formValues.email}
            onChange={handleChange}
            className={formErrors.email && "input-error"}
          />
          
          //에러시
          {formErrors.email && (
            <span className="error">{formErrors.email}</span>
          )}
        </div>
        
        //비밀번호 검사
        <div className="form-row">
          <label htmlFor="password">Password</label>
          <input
            type="password"
            name="password"
            id="password"
            value={formValues.password}
            onChange={handleChange}
            className={formErrors.password && "input-error"}
          />
          
          //에러시
          {formErrors.password && (
            <span className="error">{formErrors.password}</span>
          )}
        </div>
        <button type="submit">Sign In</button>
      </form>
    </div>
  );

리액트는 input 태그에 onChange={handleChange} 속성과 value={formValues.email} 이런식으로 사용하며 value 값을 컨트롤 할 수 있다. 그리고 에러 관련된 input 필드를 input-error 스타일로 적용한다.

에러 메시지는 조건부 렌더링을 이용하여 나타냅니다. 마지막으로 errors 객체에 오류가 있는지, isSubmitting이 참인지 확인합니다. 이러한 조건이 참이면 사용자에게 성공적으로 로그인했음을 알리는 메시지를 표시합니다.

이를 통해 완벽하게 기능과 검증 된 양식을 설정할 수 있습니다. 그러나 Yup의 도움으로 Formik과 같은 양식 라이브러리는 양식 처리의 복잡성을 더욱 더 단순화 할 수 있습니다.

Formik과 Yup에 대해서 !

💡 Formik

먼저, Formik은 양식 처리에서 가장 성가신 3가지 부분을 도와주는 작은 라이브러리입니다.

  1. 양식 상태에서 값을 가져와줍니다.
  2. 유효성 검사를 도와주고 검증에 대한 오류 메시지를 나타내줍니다.
  3. 양식 제출 처리를 해줍니다.

Formik은 유연한 라이브러리로 얼마나 사용할 지 결정할 수 있습니다. (이메일, 패스워드, 이름, 아이디 등등) 기능 또한 제어 할 수 있습니다. 그리고 HTML 입력필드 및 사용자지정 유효성 검사규칙 또는 Yup에서 제공하는 사용자지정 구성요소와 함께 사용할 수도 있습니다.

Formik은 양식 유효성 검사를 쉽게하지만, Yup과 짝을 이루면 React에서 양식 처리를 둘러싼 모든 복잡성을 추상화 해줍니다.

💡 Yup이란?

Yup은 JavaScript 객체 스키마 유효성 검사기입니다. 사용자 지정 유효성 검사 규칙을 만드는 데 어떻게 도움이되는지 중점적으로 살펴 보겠습니다. 이것은 가입 양식에 대한 샘플 Yup 객체 스키마입니다.

const SignUpSchema = Yup.object().shape({
//첫번째 이름 제어
  firstName: Yup.string()
    .min(2, "Too Short!")
    .max(50, "Too Long!")
    .required("Firstname is required"),

//다음 이름 제어
  lastName: Yup.string()
    .min(2, "Too Short!")
    .max(50, "Too Long!")
    .required("Lastname is required"),

// 핸드폰 번호 기능 제어
  phoneNumber: Yup.string()
    .required("Phone number is required")
    .matches(
/^([0]{1}|\+?[234]{3})([7-9]{1})([0|1]{1})([\d]{1})([\d]{7})$/g,
      "Invalid phone number"
    ),

// 이메일 기능 제어
  email: Yup.string().email().required("Email is required"),

// 비밀번호 기능 제어
  password: Yup.string()
    .required("Password is required")
    .min(6, "Password is too short - should be 6 chars minimum"),
});

yup과 함께 작업하니 그냥 formik만 사용한 것보다 훨씬 더 가독성이 좋고 간결화 되었어요.

💡 Formik 사용법

npm이나 yarn을 통해 formik를 설치해줍니다.

npm i formik or yarn add formik

그런 다음 사용할 파일에 formik를 임포트 시켜줍니다.

import { Formik } from "formik";

그리고 컴포넌트를 생성하기 전에 초기 값을 생성하고 설정할 때 Formik 컴포넌트에 props로 전달할 객체의 유효성을 검사해야합니다. initialValuesvalidate는 일반 단어가 아닌 코드 조각입니다.

이 작업을 수행하는 결정은 기술적 인 것이 아니라 코드의 가독성을 위한 것입니다.

const initialValues = {
  email: "",
  password: ""
};

initialValues : 각 양식 필드의 초기 값을 설명하는 객체입니다. initialValues의 각 키에 주어진 이름은 Formik에서 감시 할 입력 필드의 이름 값과 일치해야합니다.

const validate = (values) => {
  let errors = {};
  
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i;
  
  //이메일 값이 없을 경우
  if (!values.email) {
    errors.email = "Email is required";
    //정규식에 어긋나는 경우
  } else if (!regex.test(values.email)) {
    errors.email = "Invalid Email";
  }
  
   //비밀번호 값이 없을 경우
  if (!values.password) {
    errors.password = "Password is required";
    //비밀번호 길이가 4글자보다 작을 경우
  } else if (values.password.length < 4) {
    errors.password = "Password too short";
  }
  return errors;
};

validate : 데이터 폼 유효성 검사를 처리하는 함수를 받습니다. 이 함수는 데이터 값 형식의 객체를 인수로 받아들이고 정의 된 규칙에 따라 객체의 각 속성의 유효성을 검사합니다. 값 객체의 각 키는 입력 필드의 이름과 일치해야합니다.

const submitForm = (values) => {
  console.log(values);
};

onSubmit : 사용자가 제출 한 후 발생하는 작업을 처리합니다. onSubmit은 오류가 없는 경우에만 실행되는 콜백 함수를 사용합니다. 즉, 사용자 입력이 유효합니다 !

const SignInForm = () => {
  return (
  
  // initialValues : 각 양식 필드의 초기 값을 설명하는 객체
  // validate : 데이터 폼 유효성 검사를 처리하는 함수를 받음
  // onSubmit : 사용자가 제출 한 후 발생하는 작업을 처리
  // 💡 값 객체의 각 키는 입력 필드의 이름과 일치해야합니다.
    <Formik
      initialValues={initialValues}
      validate={validate}
      onSubmit={submitForm}
    >
      {(formik) => { //💡 formik props
      //💡 formik의 render API 속성들 입니다.
        const {
          values,
          handleChange,
          handleSubmit,
          errors,
          touched,
          handleBlur,
          isValid,
          dirty
        } = formik;
        return (
            <div className="container">
              <h1>Sign in to continue</h1>
              
              // 폼 제출
              <form onSubmit={handleSubmit}>
                <div className="form-row">
                  <label htmlFor="email">Email</label>
                  
                  // input 기능
                  <input
                    type="email"
                    name="email"
                    id="email"
                    value={values.email}
                    onChange={handleChange}
                    onBlur={handleBlur}
                    className={errors.email && touched.email ? 
                    "input-error" : null}
                  />
                  
                  //이메일 에러나 이메일 터치했을 때 span 실행
                  {errors.email && touched.email && (
                    <span className="error">{errors.email}</span>
                  )}
                </div>
                
                // 비밀번호
                <div className="form-row">
                  <label htmlFor="password">Password</label>
                  <input
                    type="password"
                    name="password"
                    id="password"
                    value={values.password}
                    onChange={handleChange}
                    onBlur={handleBlur}
                    className={errors.password && touched.password ? 
                     "input-error" : null}
                  />
                  //비밀번호 에러나 비밀번호 터치했을 때 span 실행
                  {errors.password && touched.password && (
                    <span className="error">{errors.password}</span>
                  )}
                </div>
                
                // 버튼 눌렀을 때, 기능 제어
                <button
                  type="submit"
                  className={dirty && isValid ? "" : "disabled-btn"}
                  disabled={!(dirty && isValid)}>
                  Sign In
                </button>
              </form>
            </div>
        );
      }}
    </Formik>
  );
};

initialValues 객체는, 앞서 정의한 submitFormvalidate 함수를 Formik의 initialValues, onSubmit , validate props에 각각 전달합니다.

render props 패턴을 사용하여 Formik API가 제공하는 더 많은 props에 접근 할 수 있습니다.

  • values : 이것은 사용자 입력 값을 보유합니다.

  • handleChange : 입력 변경 이벤트 처리기입니다. 입력 필드 input onChange = {handleChange}로 전달됩니다. 사용자 입력의 변경을 처리합니다.

  • handleSubmit : 폼 양식 제출 핸들러 form onSubmit = {props.handleSubmit} 양식으로 전달됩니다. 그러면 양식이 제출 될 때마다 onSubmit prop에 전달 된 함수가 실행됩니다.

  • errors : 이 객체는 각 입력 필드에 해당하는 유효성 검사 오류를 보유하고 있으며 Yup 객체 스키마에 전달한 정의로 채워집니다.

  • touched : 이것은 양식 필드가 터치되었는지 감시하는 객체입니다. 각 키는 입력 요소의 이름에 해당하며 부울 값을 갖습니다.

  • handleBlur : 이것은 onBlur 이벤트 핸들러이며 입력 필드 input onBlur = {handleBlur}로 전달됩니다. 사용자가 입력에서 포커스를 제거하면 이 함수가 호출됩니다. 그것이 없으면 입력이 포커스를 잃었을 때 오류가 있으면 사용자가 제출하려고 할 때만 오류가 표시됩니다.

  • isValid : 오류가 없으면 (예를들어 오류 객체가 비어 있으면) true를 반환하고 그렇지 않으면 false를 반환합니다.

  • dirty : 폼 양식을 건드렸는지 여부를 확인합니다. 양식이 처음 로드 될 때 이를 사용하여 제출 버튼을 비활성화 할 수 있습니다.

양식이 제출되면 Formik은 오류 객체에 오류가 있는지 확인합니다. 있는 경우 제출을 중단하고 오류를 표시합니다.

HTML 입력을 사용하여 범위를 표시하기 위해 필드가 터치되고 해당 필드에 오류가 있는 경우 각 입력 필드의 오류 메시지를 조건부 렌더링으로 스타일을 지정합니다.

💡 조건부 렌더링 예시

//폼 여부를 건드리지 않은 경우 그리고 오류가 있는 경우에
//disabled-btn이 나타나도록 그게 아니라면 ""

<button
  type="submit"
  className={!(dirty && isValid) ? "disabled-btn" : ""}
  disabled={!(dirty && isValid)}>
      Sign In
</button>

버튼에 시각적으로 신호를 추가 할 수 있습니다. 버튼은 조건부 스타일로 지정되며 isValid 및 dirty props를 사용하여 오류 객체에 오류가 있는 경우 비활성화 합니다.

Formik의 구성 요소를 사용한 유효성 검사와 "Yup"

yup을 설치해줍니다.

npm i yup 또는 yarn add yup

yup을 임포트 시켜줍니다.
Yup을 설치하고 Formik에서 Field, Form 및 ErrorMessage 구성 요소를 가져옵니다.

import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";

Formik은 데이터 폼 양식 유효성 검사를 쉽게 도와줍니다! Yup과 짝을 이루면 React에서 양식 처리를 둘러싼 모든 복잡성을 추상화 하지요. 그런 다음 Yup을 사용하여 로그인 양식에 사용할 스키마를 생성 할 수 있습니다.

필드 수에 따라 지루할 수 있는 사용자 지정 유효성 검사를 만드는 대신 Yup이 처리하도록 둘 수 있습니다.

const SignInSchema = Yup.object().shape({
  email: Yup.string().email().required("Email is required"),

  password: Yup.string()
    .required("Password is required")
    .min(4, "Password is too short - should be 4 chars minimum"),
});

Yup은 React에서 propTypes를 정의하는 방법과 유사하게 작동합니다. Yup의 객체 기능으로 객체 스키마를 만들었습니다. 유효성 검사 객체 스키마의 모양을 정의하고 Yup의 shape() 메서드에 전달합니다. required() 이 메서드는 문자열을 인수로 사용하며 이 문자열이 오류 메시지가 됩니다. 필수 필드가 비어있을 때마다 표시됩니다.

이 스키마에는 두 가지 속성이 있습니다.

  • 문자열 유형이며 필수(required)는 이메일 특성입니다.
  • 숫자 유형이지만 필수는 아닌 비밀번호 특성입니다.

위와 같이 체인 유효성 검사는 Yup입니다. 스키마 객체의 속성은 입력 필드의 이름과 일치합니다. 문서는 Yup에서 사용할 수있는 다양한 유효성 검사 방법으로 이동합니다.

const SignInForm = () => {
  return (
    <Formik
      initialValues={initialValues}
      validationSchema={signInSchema}
      onSubmit={(values) => {
        console.log(values);
      }}
    >
      {(formik) => {
        const { errors, touched, isValid, dirty } = formik;
        return (
          <div className="container">
            <h1>Sign in to continue</h1>
            <Form>
              <div className="form-row">
                <label htmlFor="email">Email</label>
                <Field
                  type="email"
                  name="email"
                  id="email"
                  className={errors.email && touched.email ? 
                  "input-error" : null}
                />
                <ErrorMessage name="email" component="span" className="error" />
              </div>

              <div className="form-row">
                <label htmlFor="password">Password</label>
                <Field
                  type="password"
                  name="password"
                  id="password"
                  className={errors.password && touched.password ? 
                  "input-error" : null}
                />
                <ErrorMessage
                  name="password"
                  component="span"
                  className="error"
                />
              </div>

              <button
                type="submit"
                className={!(dirty && isValid) ? "disabled-btn" : ""}
                disabled={!(dirty && isValid)}
              >
                Sign In
              </button>
            </Form>
          </div>
        );
      }}
    </Formik>
  );
};

yup 라이브러리를 설치하여 작업하니 Formik의 사용자 정의 구성요소는 작업을 훨씬 더 쉽게 만들고 작성해야하는 코드의 양을 줄입니다!

  • Formik : 다른 구성 요소를 사용할 수 있으려면 이 작업이 필요합니다.

  • Form : HTML

    요소를 래핑하는 래퍼입니다. onSubmit 메소드를 양식의 제출 이벤트에 자동으로 연결합니다.

  • Field :이것은 자동으로 폼 입력의 onChange, onBlur 및 value 속성을 Formik의 handleChange, handleBlur 및 values 객체에 각각 연결합니다. 이름 소품을 사용하여 상태와 일치시키고 자동으로 상태를 입력 값과 동기화 상태로 유지합니다. 기본적으로 HTML 입력 필드를 렌더링합니다.

  • ErrorMessage : 의 name prop에 해당하는 name prop에 제공된 값을 기반으로 해당 필드에 대한 오류 메시지 렌더링을 처리합니다. 오류가 있는 경우 오류 메시지를 표시합니다.

지금까지 formik와 yup과 함께 다루는 내용들이었습니다 😁
validationSchema을 사용하여 signInSchema를 Formik에 전달합니다.

Formik 팀은 Yup을 사용한 유효성 검사 라이브러리를 좋아합니다.
오류를 객체로 변환하고 값 및 터치 된 기능과 일치하는 validationSchema라는 Yup의 특정 라이브러리를 만들었습니다.

마무리

사용자는 데이터 폼 양식 유효성 검사를 처리하는 방법을 모르거나 신경 쓰지 않습니다. 하지만 개발자에게는 가능한 한 고통스럽지 않아야하며 Formik이 그 점에서 확실한 선택이라고 생각합니다.

React에서 데이터 폼 양식 유효성을 검사 할 때 사용할 수 있는 몇 가지 옵션을 성공적으로 살펴 보았습니다 ! Formik을 점진적으로 사용하는 방법과 양식 유효성 검사를 처리 할 때 Yup과 잘 짝을 이루는 방법도 살펴 보았습니다 😃

다음에는 실제로 적용해본 내용들을 정리해보도록 하겠습니다. 😁


formik에 대한 이해를 충분히 하기 위해 한글 버전으로 해석하여 정리해 보았습니다 ! 출처입니다.

https://www.smashingmagazine.com/2020/10/react-validation-formik-yup/

profile
아늑한 뇌공간 🧠

3개의 댓글

comment-user-thumbnail
2022년 11월 8일

감사합니다!!

답글 달기
comment-user-thumbnail
2022년 12월 8일

Thanks for sharing such a great information. Keep sharing more post like this one. Really useful and informative post. myccpay

답글 달기
comment-user-thumbnail
2023년 5월 6일

myccpay.com is ranked #234 in the Finance > Banking Credit and Lending category and #46854 Globally according to March 2023 data. Get the full myccpay.com ...
https://myccpay.info/

답글 달기