React
로 서비스를 개발하다보면 사용자 입력을 받아 처리하는 서식, 즉 Form
형태를 자주 접하게 된다.
아래는 대표적인 Form
으로, 대부분 서비스에 존재하는 로그인 기능이다.
import React, { useCallback, useState } from 'react';
const LoginForm = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onChangeEmail = useCallback(e => {
setEmail(e.target.value);
}, []);
const onChangePassword = useCallback(e => {
setPassword(e.target.value);
}, []);
const onSubmitForm = useCallback(
e => {
e.preventDefault();
console.log(email, password);
},
[email, password],
);
return (
<>
<form onSubmit={onSubmitForm}>
<label htmlFor="email">
<div>EMAIL</div>
<input type="email" id="email" name="email" value={email} onChange={onChangeEmail} />
</label>
<label htmlFor="password">
<div>PASSWORD</div>
<input type="password" id="password" name="password" value={password} onChange={onChangePassword} />
</label>
<button type="submit">LOGIN</button>
</form>
</>
);
};
export default LoginForm;
Form
은 작성하는 것은 물론 Form item
별로 유효성검사와 같은 부가적인 기능을 추가하게 되면 체크 로직으로 인하여 코드가 매우 복잡해진다.
Formik
, Yup
은 이러한 단점을 해결하기 위해 사용되는 Form
, 유효성 검사 라이브러리이다.
번거로운
Form
작업을 편리하게 해주는 라이브러리
React
에서 Form
을 관리하기 까다로운 만큼 이를 도와주는 라이브러리의 종류는 다양하다.
그 중 Formik
는 다른 라이브러리들에 비해 성능이나 추론, 리펙토링...등등 많은 부분에서 우위를 점하고 있다.
Formik
공식문서에서는 Form
작업시 번거로운 3가지 작업을 언급하며, 이를 도와주는 라이브러리라고 설명되어 있다.
Form
의 Value
가져오기
유효성 검사 및 오류 메세지
Form Submit Handling
Yup
은 Form
의 유효성 검사를 위한 라이브러리이며, 주로 Formik
와 함께 React Form
작업을 도와준다.
Yup
은 아래 2가지 과정을 통해 Validation
을 진행한다.
1.
Yup Formatted Object
를 생성 → 개발자가 의도한 스키마와 닮아있는 객체를 생성
2.Yup Utility Function
을 통해 데이터 객체가 스키마와 매치되는지 확인
아래 npm명령어를 통해 Formik
, Yup
관련 패키지를 설치한다.
npm i formik
npm i yup
Form
에서 사용 할 상태의 초기 값을 initialValues
를 통해 설정한 뒤 value
속성으로 input
과 연결한다.
const formik = useFormik({
initialValues: {
email: '',
password: '',
},
});
<label htmlFor="email">
<div>EMAIL</div>
<input type="text" id="email" name="email" value={formik.values.email} />
</label>
<label htmlFor="password">
<div>PASSWORD</div>
<input type="password" id="password" name="password" value={formik.values.password} />
</label>
input
값이 변경 될 때 사용하는 onChange
는 formik
의 handleChange
속성을 통해 연결한다.
이 때 handleChange
는 위에서 설정한 values[key]
값이 업데이트된다.
<label htmlFor="email">
<div>EMAIL</div>
<input
type="text"
id="email"
name="email"
value={formik.values.email}
onChange={formik.handleChange}
/>
</label>
<label htmlFor="password">
<div>PASSWORD</div>
<input
type="password"
id="password"
name="password"
value={formik.values.password}
onChange={formik.handleChange}
/>
</label>
Form Submit
이벤트 리스너 연결은 <form>
태그 onSubmit
속성에 연결하며, handleSubmit
속성을 사용한다.
또한 submit
에 사용되는 함수도 초기값과 함께 작성한다.
<form onSubmit={formik.handleSubmit}>
<label htmlFor="email">
<div>EMAIL</div>
<input
type="text"
id="email"
name="email"
value={formik.values.email}
onChange={formik.handleChange}
/>
</label>
<label htmlFor="password">
<div>PASSWORD</div>
<input
type="password"
id="password"
name="password"
value={formik.values.password}
onChange={formik.handleChange}
/>
</label>
<button type="submit">LOGIN</button>
</form>
const formik = useFormik({
initialValues: {
email: '',
password: '',
},
onSubmit: e => {
console.log(e);
},
});
입력한 값의 유효성 검사를 하기 위해 사용자 정의 유효성 검사 함수를 생성한 뒤 validate
로 useFormik hook
에 연결한다.
이 때 useFomik
에 전달한 onSubmit
함수는 오류가 없는 경우에만 실행된다.
const validate = values => {
const errors = {};
const emailRule = /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;
if (!values.email) {
errors.email = '이메일을 입력해주세요.';
} else if (!emailRule.test(values.email)) {
errors.email = '이메일 형식이 올바르지 않습니다.';
}
if (!values.password) {
errors.password = '비밀번호를 입력해주세요.';
}
return errors;
};
const formik = useFormik({
initialValues: {
email: '',
password: '',
},
onSubmit: e => {
console.log(e);
},
validate,
});
위의 코드를 실행해보면 첫 입력부터 에러를 발생시켜 좋지 않은 UX(User Experience)
를 발생시킨다.
위와 같은 문제점을 해결하기 위해서는 touched
속성을 사용하여 사용자가 한 번이상 입력한 뒤에 유효성을 검사하도록 설정할 수 있다.
<label htmlFor="email">
<div>EMAIL</div>
<input type="text" id="email" name="email" value={formik.values.email} onChange={formik.handleChange} />
</label>
{formik.touched.email && formik.errors.email && <div>{formik.errors.email}</div>}
Yup
을 사용한 유효성 검사는 기존 validate
를 대신해 validationSchema
를 사용한다.
아래 코드를 보면 확인할 수 있듯 Yup
을 사용하면 Formik Validate
에 비해 코드의 양을 많이 줄일 수 있다.
const validationSchema = Yup.object({
email: Yup.string().email('이메일 형식이 올바르지 않습니다.').required('Required'),
password: Yup.string().max(10, '비밀번호는 최대 10글자입니다.').required('Required'),
});
const formik = useFormik({
initialValues: {
email: '',
password: '',
},
onSubmit: e => {
console.log(e);
},
validationSchema,
});
useFormik
는 getFieldProps
를 사용하여 좀 더 빠른 적용을 지원한다.
<label htmlFor="email">
<div>EMAIL</div>
<input
type="text"
id="email"
name="email"
// value={formik.values.email}
// onChange={formik.handleChange}
{...formik.getFieldProps('email')}
/>
</label>
{formik.touched.email && formik.errors.email && <div>{formik.errors.email}</div>}
Formik
는 기존 Form
을 컨트롤하기 위해 아래와 같은 컴포넌트들을 제공한다.
import { Formik, Form, Field, ErrorMessage } from 'formik'
기본적으로 Field
는 input
을 렌더링 하며, name props
를 전달하면 암시적으로 각각의 onChange
, onBlur
, value props
를 연결한다.
이 외에도 as
, className
...등의 props
도 사용 가능하다.
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={onSubmit}>
<Form>
<label htmlFor="email">
<div>EMAIL</div>
<Field
type="text"
id="email"
name="email"
// className
// as
/>
<ErrorMessage name='name' component={<ErrorComponent />} />
</label>
</Form>
</Formik>
또한 component
속성에 커스텀 컴포넌트를 연결하면 아래와 같이 ErrorMessage
컴포넌트를 커스텀할 수 있다.
const ErrorComponent = props => <div {...props}></div>
oneOf
는 Yup
라이브러리 메서드로, 배열 입력값 중 하나를 선택할 때 사용할 수 있다.
nickname: Yup.string().oneOf(['user1', 'user2', 'user3']);
Formik: Build forms in React, without the tears
Yup - npm
React Formik Tutorial with Yup (React Form Validation)