이제 유효성 검사를 추가한 formik을 살펴보자.
yup을 쓰는건 아니고, 먼저 기본적으로 if 문을 사용하여 유효성 검사를 하는 형태다.
import React from 'react';
import { useFormik } from 'formik';
// 커스텀한 유효성검사 함수. 얘네는 반드시 우리의 값/초깃값에 대칭되는 객체를 반환한다.
const validate = values => {
const errors = {};
if (!values.firstName) {
errors.firstName = 'Required';
} else if (values.firstName.length > 15) {
errors.firstName = 'Must be 15 characters or less';
}
if (!values.lastName) {
errors.lastName = 'Required';
} else if (values.lastName.length > 20) {
errors.lastName = 'Must be 20 characters or less';
}
if (!values.email) {
errors.email = 'Required';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid email address';
}
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}
value={formik.values.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}
value={formik.values.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}
value={formik.values.email}
/>
{formik.errors.email ? <div>{formik.errors.email}</div> : null}
<button type="submit">Submit</button>
</form>
);
};
커스텀한 유효성검사 함수 validate를 만들고, 그 안에 initialValue 중 유효성 검사가 필요한 애들을 조건문으로 정의한다.
useformik 에서 initialValues 다음 validate를 부른다.
이제 input 값을 작성하고 다음 input을 작성할 때 조건이 맞지 않는다면 에러가 뜬다.
이때 onSubmit은 당연하게도 에러가 없어야 실행이 된다.
(영상은 css가 하나도 없어서 구리네)
근데 아쉬운점은 하나의 인풋값을 작성하는 순간 모든 유효성검사의 친구들이 반응한다는 점이다.
뭔가 아쉽다!
계속 나아가보자.
위에 아쉬운점에 언급했듯, 보통 우리는 인풋값을 작성했을 때 값이 유효한지에 대해 해당 인풋값만 에러메세지를 뱉길 원한다. 그렇게 만들어보자.
formik은 에러나 값에 관련해서 계속해서 추척한다. 이 정보를 touched라는 객체에 저장한다.
touched
: touch 객체이며, values/initialValues의 모양도 미러링하는 저장된다. touch의 키는 필드 이름이고, touch의 값은 참/거짓 이다. 터치를 활용하기 위해 formik.handleBlur를 각 입력의 onBlur prop에 전달한다. 이 함수는 이름 속성을 사용하여 업데이트할 필드를 파악한다는 점에서 formik.handleChange와 유사하게 작동한다.
import { useFormik } from 'formik';
const validate = values => {
const errors = {};
if (!values.firstName) {
errors.firstName = 'Required';
} else if (values.firstName.length > 15) {
errors.firstName = 'Must be 15 characters or less';
}
if (!values.lastName) {
errors.lastName = 'Required';
} else if (values.lastName.length > 20) {
errors.lastName = 'Must be 20 characters or less';
}
if (!values.email) {
errors.email = 'Required';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid email address';
}
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.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.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.errors.email ? <div>{formik.errors.email}</div> : null}
<button type="submit">Submit</button>
</form>
);
};
onBlur={formik.handleBlur}
별거 없다. 기존 거에서 해당 부분만 추가되어있다.
딱 여기까지만 쓰면 하나만 입력해도 모든 유효성검사가 튀어나오는 맨 처음 작성한 것과 다를바 없다.
여기서 에러 메세지를 touched로 검사하는 한 줄이 더 추가되어야 한다.
import React from 'react';
import { useFormik } from 'formik';
const validate = values => {
const errors = {};
if (!values.firstName) {
errors.firstName = 'Required';
} else if (values.firstName.length > 15) {
errors.firstName = 'Must be 15 characters or less';
}
if (!values.lastName) {
errors.lastName = 'Required';
} else if (values.lastName.length > 20) {
errors.lastName = 'Must be 20 characters or less';
}
if (!values.email) {
errors.email = 'Required';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid email address';
}
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을 사용하여 유효성 검사하는 편을 작성해보려한다.
이렇게 끊어서 차근차근 보면 좀 더 이해되는 것 같다.