[React] react-hook-form yup으로 validation 처리하기
이전 게시글에서 react-hook-form을 사용하면 얼마나 간단하게 form 처리를 할 수 있는지 알아보았습니다.
그 과정에서 에러 핸들링에 대해서도 간단하게 처리할 수 있는 것을 확인하였습니다.
그래도 불편한 점이 있습니다.
<input
{...register("name", {
required: "이름은 필수 값입니다.",
minLength: {
value: 5,
message: "이름은 5글자 이상이어야합니다."
},
maxLength: {
value: 10,
message: "이름은 10글자 이하이어야 합니다."
}
})}
/>;
위 코드를 확인해보면 코드 중간에 에러 처리를 해주어야 한다는 것입니다.
물론 최상단에 변수로 따로 빼서 처리하면 되지만 불편합니다.
이러한 불편함을 해결해주고 더 간단하게 에러 핸들링을 할 수 있도록 도와주는 yup 라이브러리가 있습니다.
이번 게시글에서는 yup을 통해 이전 게시글에서 했던 에러 핸들링을 더 깔끔하게 해보겠습니다.
yup 설치하기
yup을 사용하기 위해 필요한 설치 명령어입니다.
yup : npm install yup or yarn add yup
yupResolver : npm install @hookform/resolvers/yup or yarn add @hookform/resolvers/yup
yup 문서입니다.
자세한 사용법은 해당 문서를 보시기 바랍니다.
yup 사용하여 기존 코드 리팩토링하기
◆ yup schema 생성 및 react-hook-form 연결
우선 schema 생성과 react-hook-form에 설정하는 방법을 알아보겠습니다.
schema는 간단하게 설명하면 yup에서 validation을 할 수 있게 우리가 작성해주는 것입니다.
따라서 schema를 type과 개발자가 원하는 validation에 맞게 잘 작성해주어야 합니다.
여기서 required, max, min, pattern 등 많은 함수 활용이 가능합니다.
그리고 구현한 schema를 react-hook-form에 등록해주어야 합니다.
해당 작업들은 모두 간단하니 아래 코드를 확인해봅시다.
import { yupResolver } from "@hookform/resolvers/yup";
import { object, SchemaOf } from "yup";
import { IUserData } from "./types";
const schema: SchemaOf<IUserData> = object({
// ... 추후 작성해야함.
});
const {
register,
handleSubmit,
formState: { errors }
} = useForm<IUserData>({
mode: "onSubmit",
resolver: yupResolver(schema)
});
위 코드를 보시면 tsx이기 때문에 schema에 SchemaOf를 이용하여 type을 작성한 것을 확인할 수 있습니다.
현재 데이터 구조는 객체이기 때문에 object로 감싸주었습니다.
(추후 상세 schema 작성)
react-hook-form에 연결하는 방법은 resolver에 추가해주시면 끝입니다.
◆ yup schema 구현하기
이제 schema를 상세 구현해보겠습니다.
name, age, id, password, email 순서로 구현하겠습니다.
- name
name의 경우 조건이 required, minLength, maxLength가 있었습니다.
아래처럼 작성하시면 됩니다.
const schema: SchemaOf<IUserData> = object({
name: string()
.required("이름은 필수 값입니다.")
.min(5, "이름은 5글자 이상이어야합니다.")
.max(10, "이름은 10글자 이하이어야 합니다.")
});
위 코드만 보면 쉽게 이해가 가능하여 따로 설명은 하지 않겠습니다.
(해당 함수 사용은 공식 문서에 잘 나와있습니다.)
추가로 schema에 validation을 모두 작성하였기 때문에 react-hook-form에서 input에 적어주었던 validation들은 모두 지워주어도 됩니다.
아래 yup 적용 전/후 코드를 비교해봅시다.
yup 적용 전 코드
<input
{...register("name", {
required: "이름은 필수 값입니다.",
minLength: {
value: 5,
message: "이름은 5글자 이상이어야합니다."
},
maxLength: {
value: 10,
message: "이름은 10글자 이하이어야 합니다."
}
})}
placeholder="name"
/>
yup 적용 후 코드
<input {...register("name")} placeholder="name" />
yup 적용 전/후 코드를 보시면 코드 길이가 많이 차이 나는 것을 확인할 수 있습니다.
가독성이 굉장히 좋아진 것을 확인할 수 있습니다.
(추후 위처럼 상세 비교는 없음)
(schema 작업은 계속 합쳐짐)
- age
age의 경우 조건이 required, min, max가 있었습니다.
해당 조건을 작성한 schema는 아래와 같습니다.
const schema: SchemaOf<IUserData> = object({
name: string()
.required("이름은 필수 값입니다.")
.min(5, "이름은 5글자 이상이어야합니다.")
.max(10, "이름은 10글자 이하이어야 합니다."),
age: number()
.required("나이는 필수 값입니다.")
.min(10, "나이는 10살 이상이어야 합니다.")
.max(100, "나이는 100살 이하이어야 합니다.")
});
- id
id의 경우 required만 필요합니다.
const schema: SchemaOf<IUserData> = object({
name: string()
.required("이름은 필수 값입니다.")
.min(5, "이름은 5글자 이상이어야합니다.")
.max(10, "이름은 10글자 이하이어야 합니다."),
age: number()
.required("나이는 필수 값입니다.")
.min(10, "나이는 10살 이상이어야 합니다.")
.max(100, "나이는 100살 이하이어야 합니다."),
id: string().required("id는 필수 값 입니다.")
});
- password
password의 경우 required, 영어만 가능 조건이 있습니다.
여기서 영어를 체크하는 것은 정규식을 사용했습니다.
const schema: SchemaOf<IUserData> = object({
name: string()
.required("이름은 필수 값입니다.")
.min(5, "이름은 5글자 이상이어야합니다.")
.max(10, "이름은 10글자 이하이어야 합니다."),
age: number()
.required("나이는 필수 값입니다.")
.min(10, "나이는 10살 이상이어야 합니다.")
.max(100, "나이는 100살 이하이어야 합니다."),
id: string().required("id는 필수 값 입니다."),
password: string()
.required("비밀번호는 필수 값입니다.")
.matches(/^[a-zA-Z]*$/, { message: "비밀번호는 영어만 가능합니다." })
});
yup에서는 정규식을 사용할 때 matches 함수를 사용하시면 됩니다.
보여주고 싶은 message는 2번째 인자로 넘겨주시면 됩니다.
email의 경우 gmail만 가능하도록 되어 있습니다.
이 경우 test 함수를 사용하시면 쉽게 validation 하실 수 있습니다.
const schema: SchemaOf<IUserData> = object({
name: string()
.required("이름은 필수 값입니다.")
.min(5, "이름은 5글자 이상이어야합니다.")
.max(10, "이름은 10글자 이하이어야 합니다."),
age: number()
.required("나이는 필수 값입니다.")
.min(10, "나이는 10살 이상이어야 합니다.")
.max(100, "나이는 100살 이하이어야 합니다."),
id: string().required("id는 필수 값 입니다."),
password: string()
.required("비밀번호는 필수 값입니다.")
.matches(/^[a-zA-Z]*$/, { message: "비밀번호는 영어만 가능합니다." }),
email: string()
.required("email은 필수 값 입니다.")
.test("domainCheck", "gmail만 가능합니다.", email => {
if (!email) return false;
return email.split("@")[1] === "gmail.com";
})
});
test 함수를 사용하는 방법도 매우 쉽습니다.
인자로 test명, message, validation function을 넘겨주시면 됩니다.
위 모든 작업을 끝낸 코드는 아래와 같습니다.
import { yupResolver } from "@hookform/resolvers/yup";
import { FieldErrors, useForm } from "react-hook-form";
import { number, object, SchemaOf, string } from "yup";
import { IUserData } from "./types";
const schema: SchemaOf<IUserData> = object({
name: string()
.required("이름은 필수 값입니다.")
.min(5, "이름은 5글자 이상이어야합니다.")
.max(10, "이름은 10글자 이하이어야 합니다."),
age: number()
.required("나이는 필수 값입니다.")
.min(10, "나이는 10살 이상이어야 합니다.")
.max(100, "나이는 100살 이하이어야 합니다."),
id: string().required("id는 필수 값 입니다."),
password: string()
.required("비밀번호는 필수 값입니다.")
.matches(/^[a-zA-Z]*$/, { message: "비밀번호는 영어만 가능합니다." }),
email: string()
.required("email은 필수 값 입니다.")
.test("domainCheck", "gmail만 가능합니다.", email => {
if (!email) return false;
return email.split("@")[1] === "gmail.com";
})
});
const UserRegisterRhfWithYup = () => {
const {
register,
handleSubmit,
formState: { errors }
} = useForm<IUserData>({
mode: "onSubmit",
resolver: yupResolver(schema)
});
const onValid = (data: IUserData) => {
console.log("# onValid", data);
};
const onInValid = (errors: FieldErrors) => {
console.log("# onInValid", errors);
};
return (
<form onSubmit={handleSubmit(onValid, onInValid)}>
<input {...register("name")} placeholder="name" />
<span>{errors.name?.message}</span>
<br />
<input type="number" {...register("age")} placeholder="age" />
<span>{errors.age?.message}</span>
<br />
<input {...register("id")} placeholder="id" />
<span>{errors.id?.message}</span>
<br />
<input {...register("password")} type="password" placeholder="password" />
<span>{errors.password?.message}</span>
<br />
<input {...register("email")} type="email" placeholder="email" />
<span>{errors.email?.message}</span>
<br />
<input type="submit" />
</form>
);
};
export default UserRegisterRhfWithYup;
한눈에 딱 봐도 return 문이 훨씬 간단해졌습니다.
그리고 validation 부분이 따로 분리되어 있어 가독성도 좋습니다.
정리
이번 게시글에서는 yup에 대해 알아보았습니다.
react-hook-form으로도 충분히 좋지만 yup을 사용하면 validation을 쉽고 간결하게 할 수 있습니다.
yup은 공식문서가 나름 잘 되어 있으니 사용하시기 전 한번 읽어보시길 바랍니다.
참고자료
마지막
해당 내용은 틀릴 수도 있습니다. 틀린 내용이 있으면 조언 부탁드립니다.
'기타 (+ Legacy) > Legacy' 카테고리의 다른 글
[Nest] NestJS + GraphQL + MongoDB 구현하기 (0) | 2023.03.23 |
---|---|
[React] 키보드 이벤트 처리 (0) | 2023.02.09 |
[React] useEffect 실습 (0) | 2022.06.17 |
[React] useEffect 개념 (0) | 2022.06.15 |
[React] useRef 개념 및 실습 (0) | 2022.06.13 |