[React] # 8 Form

simoniful·2021년 7월 7일
0

React

목록 보기
8/13
post-thumbnail

HTML 폼 엘리먼트는 폼 엘리먼트 자체가 내부 상태를 가지기 때문에, React의 다른 DOM 엘리먼트와 다르게 동작합니다. 폼을 제출하면 새로운 페이지로 이동하는 기본 HTML 폼 동작을 수행하는 것이 기본이며, 대부분의 경우 JavaScript 함수로 폼의 제출을 처리하고 사용자가 폼에 입력한 데이터에 접근하도록 제어합니다.

제어 컴포넌트 (controlled components)

React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState() 혹은 useState()에 의해 업데이트됩니다. 따라서 해당 <input>onChange 속성과 <form>onSubmit 속성을 통해서 state를 업데이트하고 관리함을 통하여 다른 UI 엘리먼트에 input의 값을 전달하거나 다른 이벤트 핸들러에서 값을 재설정할 수 있습니다.

👉🏻 React Official Form

공식 문서를 통하여 Html과의 차이점과 React 환경에서 이를 활용하고 computed property name을 통한 state 간소화를 배울 수 있습니다.

function NameForm (props) {
  const [value, setValue] = React.useState('');
  
  function handleChange(event) {
    setValue(event.target.value);
  }
  
  function handleSubmit(event) {
    event.preventDefault();
    alert('A name was submitted: ' + value);
  }
  
  return (
      <form onSubmit={handleSubmit}>
        <label>
          Name:
          <input type="text" value={value} onChange={handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
}

ReactDOM.render(
  <NameForm />,
  document.getElementById('root')
);

Formik

Formik은 React Native에서 컴포넌트를 빌드하기 위한 React 구성 요소 및 hooks의 작은 그룹입니다. 설치를 통해서 유효성 검사, 방문한 필드 추적 및 폼 제출 처리와 같은 절차를 간소화하고 제어 컴포넌트 및 state 관리에 기초하여 활용할 수 있습니다.

👉🏻 Formik을 활용한 회원가입 예제

  • form 내부 input의 변화 및 상태에서 값 가져오기
  • 유효성 검사 및 에러 메세지
  • form submit 핸들링

npm install formik --save
npm install yup --save

 import React from 'react';
 import { useFormik } from 'formik';
 
 const SignupForm = () => {
   // 데이터 형식에 맞추어 초기화하여 react에서 초기 렌더링 시 발생할 수 있는 에러를 방지합니다.
   const formik = useFormik({
     initialValues: {
       firstName: '',
       lastName: '',
       email: '',
     },
     onSubmit: values => {
       alert(JSON.stringify(values, null, 2));
     },
   });
   return (
     <form onSubmit={formik.handleSubmit}>
       <label htmlFor="firstName">First Name</label>
       <input
         id="firstName"
         name="firstName"
         type="text"
         onChange={formik.handleChange}
         value={formik.values.firstName}
       />
 
       <label htmlFor="lastName">Last Name</label>
       <input
         id="lastName"
         name="lastName"
         type="text"
         onChange={formik.handleChange}
         value={formik.values.lastName}
       />
 
       <label htmlFor="email">Email Address</label>
       <input
         id="email"
         name="email"
         type="email"
         onChange={formik.handleChange}
         value={formik.values.email}
       />
 
       <button type="submit">Submit</button>
     </form>
   );
 };

useFormik hook은 formik변수에 폼의 상태와 여러가지의 helper 메소드를 리턴합니다. 대표적으로 다음과 같은 3가지 메서드가 있습니다.

  • handleSubmit : onSubmit 핸들러
  • handleChange : 각 <input>, <select> 또는 <textarea>에 전달하는 change핸들러
  • values : <input>의 현재 value

이 메서드를 활용하여 기존 Html 형식으로 핸들링했던 방식과 동일하게 이를 컨트롤 가능하며, 초기값에 설정한 key 값과 동일하게 설정하므로 일치하는 ID 및 이름 HTML 특성을 전달합니다. 따라서, 동일한 이름(email -> formik.values.email)을 사용하여 해당 input에 액세스합니다.

const [values, setValues] = React.useState({});
 
const handleChange = event => {
  setValues(prevValues => ({
    ...prevValues,
    // 업데이트 할 `values`의 키를 formik에게 전달하기 위해 name prop을 사용
    [event.target.name]: event.target.value
  });
}

<input>의 name을 기반으로 한 ES6의 computed property name 구문을 사용하고 있습니다.기존 값과 갱신 값을 state로 관리합니다.


유효성 검사

기본적인 Html의 제한점은 크게 3가지 있습니다.

첫째, 브라우저에서만 작동하기에 React Native 환경에서 제약이 있습니다.
둘째, 지정 사용자에게 꼭 맞는 오류 메세지를 표시하는 것은 어렵거나 불가능합니다.
셋째, 동작에 있어서 버벅거림과 이상함이 있습니다.

Formik을 통하여 양식의 값뿐만 아니라 양식의 검증 및 오류 메시지도 추적 가능합니다. JS로 검증을 추가하려면 유효성 검증 함수를 선언하고 useFormik() Hook에 이를 전달하여 검증을 하는 것이 가능합니다. 이 때 유효성 검증 함수는 values와 initialValues와 똑같은 모양의 오류 객체를 만들어 냅니다.

// 유효성 검증 함수 
// values와 initialValues와 똑같은 모양의 오류 객체 리턴
const validate = values => {
   const errors = {};
 
   if (!values.firstName) {
     errors.firstName = '필수 작성 항목입니다';
   } else if (values.firstName.length > 15) {
     errors.firstName = '15자 이내로 작성해주세요';
   }
 
   if (!values.lastName) {
     errors.lastName = '필수 작성 항목입니다';
   } else if (values.lastName.length > 20) {
     errors.lastName = '20자 이내로 작성해주세요';
   }
 
   if (!values.email) {
     errors.email = '필수 작성 항목입니다';
   } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
     errors.email = '유효하지 않은 이메일 양식입니다';
   }
 
   return errors;
 };
 
 const SignupForm = () => {
   const formik = useFormik({
     initialValues: {
       firstName: '',
       lastName: '',
       email: '',
     },
     validate,
     onSubmit: values => {
       alert(JSON.stringify(values, null, 2));
     },
   });
   return (
     <form onSubmit={formik.handleSubmit}>
       <label htmlFor="firstName">First Name</label>
       <input
         id="firstName"
         name="firstName"
         type="text"
         onChange={formik.handleChange}
         onBlur={formik.handleBlur}
         value={formik.values.firstName}
       />
       // 유효성 메세지 부분
       {formik.touched.firstName && formik.errors.firstName ? (
         <div>{formik.errors.firstName}</div>
       ) : null}
 
       <label htmlFor="lastName">Last Name</label>
       <input
         id="lastName"
         name="lastName"
         type="text"
         onChange={formik.handleChange}
         onBlur={formik.handleBlur}
         value={formik.values.lastName}
       />
       // 유효성 메세지 부분
       {formik.touched.lastName && formik.errors.lastName ? (
         <div>{formik.errors.lastName}</div>
       ) : null}
 
       <label htmlFor="email">Email Address</label>
       <input
         id="email"
         name="email"
         type="email"
         onChange={formik.handleChange}
         onBlur={formik.handleBlur}
         value={formik.values.email}
       />
       // 유효성 메세지 부분
       {formik.touched.email && formik.errors.email ? (
         <div>{formik.errors.email}</div>
       ) : null}
       <button type="submit">Submit</button>
     </form>
   );
 };

또한, 사용에 있어서 Yup이라는 추가적인 라이브러리를 통하여 보다 코드를 간결화하는 것이 가능합니다. 간편하게 유효성 검증에 대한 함수를 대체할 수 있고

npm install yup --save

const formik = useFormik({
     initialValues: {
       firstName: '',
       lastName: '',
       email: '',
     },
     // 안으로 들어가버린 유효성 검증 함수, 보다 간결해진 코드!
     validationSchema: Yup.object({
       firstName: Yup.string()
         .max(15, 'Must be 15 characters or less')
         .required('Required'),
       lastName: Yup.string()
         .max(20, 'Must be 20 characters or less')
         .required('Required'),
       email: Yup.string().email('Invalid email address').required('Required'),
     }),
     onSubmit: values => {
       alert(JSON.stringify(values, null, 2));
     },
   });

Reducing Boilerplate

getFieldProps() 메소드를 통하여 공통 사항에 대한 코드 볼륨을 줄일 수 있습니다.

<label htmlFor="firstName">First Name</label>
<input
  id="firstName"
  name="firstName"
  type="text"
  onChange={formik.handleChange}
  onBlur={formik.handleBlur}
  value={formik.values.firstName}
/>
{formik.touched.firstName && formik.errors.firstName ? (
<div>{formik.errors.firstName}</div>
) : null}
       
       
       
<label htmlFor="firstName">First Name</label>
<input
  id="firstName"
  type="text"
  {...formik.getFieldProps('firstName')}
/>
{formik.touched.firstName && {formik.touched.firstName && formik.errors.firstName ? (
<div>{formik.errors.firstName}</div>
) : null}
     

onBlur, onFocus 이벤트

Json Object 관련 method

React Context

profile
소신있게 정진합니다.

0개의 댓글