728x90
SMALL

출처: https://www.react-hook-form.com/media

Overview

폼 유효성 검사는 사용자 입력의 정확성과 데이터의 무결성을 보장하기 위한 필수적인 과정입니다. 하지만 복잡한 폼일수록 이 검사를 효율적으로 처리하기 어렵습니다. React Hook Form은 React에서 폼을 쉽게 관리할 수 있도록 돕는 라이브러리로, 간단한 API와 뛰어난 성능을 제공합니다. 하지만 폼 검증을 더욱 최적화하려면, Yup이나 Zod와 같은 유효성 검증 라이브러리와 결합하는 것이 필요합니다.

이 글에서는 Yup이 무엇인지, 왜 사용하는지, 그리고 Zod와 비교했을 때 어떤 차이점이 있는지 살펴보겠습니다. 또한, React Hook Form과 함께 Yup을 사용하여 폼 검증을 구현하는 방법을 예시를 통해 보여드리겠습니다.

 

Yup이란 무엇이며 왜 사용하는가?

Yup은 자바스크립트 객체의 스키마를 정의하고 유효성을 검증할 수 있는 라이브러리입니다. 복잡한 유효성 검증 로직을 간단하게 구현할 수 있도록 개발자 친화적인 API를 제공합니다.

Yup의 주요 장점은 다음과 같습니다:

  1. 유연성 : 다양한 데이터 타입과 유효성 검사 규칙을 지원합니다. 문자열, 숫자, 배열 등 여러 타입의 유효성 검사를 설정할 수 있습니다.
  2. 체이닝 : 메서드 체이닝을 지원하여, 여러 유효성 검증 규칙을 간편하게 연결할 수 있습니다. 이를 통해 읽기 쉬운 코드를 작성할 수 있습니다.
  3. 비동기 유효성 검사 : 비동기 유효성 검사를 지원합니다.

 

사용 방법

React Hook Form과 Yup을 함께 사용하는 방법을 예시를 통해 살펴보겠습니다. 먼저, 프로젝트에 Yup과 React Hook Form을 설치해야 합니다:


    
npm install @hookform/resolvers yup react-hook-form

 

React Hook Form이 데이터를 관리하고, Yup이 유효성 검증을 처리하는 구조

 

이제 Yup을 사용하여 폼 스키마를 정의하고, React Hook Form과 결합해 이메일과 비밀번호 입력 폼을 구현해 보겠습니다:


    
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
const validationSchema = yup.object({
email: yup.string().email('올바른 이메일 형식이 아닙니다').required('이메일을 입력해주세요'),
password: yup.string().min(6, '비밀번호는 최소 6자 이상이어야 합니다').required('비밀번호를 입력해주세요'),
});
const MyForm = () => {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: yupResolver(validationSchema),
});
const onSubmit = (data) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>이메일</label>
<input {...register('email')} />
{errors.email && <p>{errors.email.message}</p>}
</div>
<div>
<label>비밀번호</label>
<input {...register('password')} />
{errors.password && <p>{errors.password.message}</p>}
</div>
<button type="submit">제출</button>
</form>
);
};

위 코드에서는 yupResolver를 사용하여 Yup 스키마를 React Hook Form에 통합했습니다. 폼 필드가 Yup 스키마에 정의된 유효성 검사를 따르게 되고, 에러 메시지도 설정한 대로 표시됩니다.

 

validate prop을 사용하는 것과 Yup을 사용했을 때의 차이점?

React Hook Form에서는 기본적으로 Controller 컴포넌트를 사용하여 폼 필드를 제어합니다. 이때 validate prop을 통해 개별 필드의 유효성을 직접 설정할 수 있지만, 폼이 복잡해지면 각 필드마다 개별 검증 규칙을 설정하는 것이 비효율적일 수 있습니다.

 

다음은 validate prop을 사용한 간단한 예시입니다:


    
<Controller
name="email"
control={control}
rules={{
validate: (value) => value.includes('@') || '올바른 이메일 형식이 아닙니다',
}}
render={({ field }) => <input {...field} />}
/>
<Controller
name="password"
control={control}
rules={{
validate: (value) => value.length >= 8 || '비밀번호는 최소 8자리 이상이어야 합니다.',
}}
render={({ field }) => <input {...field} />}
/>

위 코드는 간단한 유효성 검사를 설정한 예시입니다. 하지만, 각 필드마다 검증 규칙을 직접 작성해야 하므로 관리가 어려워질 수 있습니다.

 

다음은 Yup을 사용한 간단한 예시입니다:


    
const validationSchema = yup.object({
email: yup.string()
.email('올바른 이메일 형식이 아닙니다')
.required('이메일을 입력해주세요'),
password: yup.string()
.min(8, '비밀번호는 최소 8자리 이상이어야 합니다.')
.required('비밀번호를 입력해주세요.'),
});

Yup을 사용하면 스키마 객체를 통해 폼의 유효성 검사를 한 곳에서 정의할 수 있으며, React Hook Form과 결합하여 훨씬 더 효율적이고 재사용 가능한 코드를 작성할 수 있습니다.

 

조금 더 복잡한 조건일 때를 보시죠!

아래 동일한 유효성 조건을 react hook form만 사용했을 때와 yup사용했을 때를 비교해 보겠습니다.

  • 출발 시간은 오늘 이후여야 한다.
  • 출발 시간은 도착 시간보다 전이어야 한다.
  • 도착 시간은 출발 시간 이후여야 한다.
  • 도착 시간은 3개월 이후를 선택할 수 없다.

 

다음은 validate prop을 사용한 간단한 예시입니다:


    
...
const today = dayjs().startOf('day');
const maxDate = dayjs().add(3, 'month').endOf('day');
...
<label>출발 시간:</label>
<Controller
name="departureTime"
control={control}
rules={{
required: '출발 시간을 입력해주세요.',
validate: {
afterToday: value =>
dayjs(value).isAfter(today) || '출발 시간은 오늘 이후여야 합니다.',
beforeArrival: value =>
!departureTime || dayjs(value).isBefore(watch('arrivalTime')) || '출발 시간은 도착 시간보다 전이어야 합니다.'
},
}}
render={({ field }) => (
<input type="datetime-local" {...field} />
)}
/>
<label>도착 시간:</label>
<Controller
name="arrivalTime"
control={control}
rules={{
required: '도착 시간을 입력해주세요.',
validate: {
afterDeparture: value =>
dayjs(value).isAfter(departureTime) || '도착 시간은 출발 시간 이후여야 합니다.',
withinThreeMonths: value =>
dayjs(value).isBefore(maxDate) || '도착 시간은 3개월 이내여야 합니다.',
},
}}
render={({ field }) => (
<input type="datetime-local" {...field} />
)}
/>

 

다음은 Yup을 사용한 간단한 예시입니다:


    
// 오늘 날짜와 3개월 이후 날짜
const today = dayjs().startOf('day');
const maxDate = dayjs().add(3, 'month').endOf('day');
// yup 스키마 설정
const schema = Yup.object().shape({
departureTime: Yup.date()
.required('출발 시간을 입력해주세요.')
.min(today.toDate(), '출발 시간은 오늘 이후여야 합니다.')
.max(Yup.ref('arrivalTime'), '출발 시간은 도착 시간보다 전이어야 합니다.'),
arrivalTime: Yup.date()
.required('도착 시간을 입력해주세요.')
.min(Yup.ref('departureTime'), '도착 시간은 출발 시간 이후여야 합니다.')
.max(maxDate.toDate(), '도착 시간은 3개월 이내여야 합니다.'),
});
...
const { ... } = useForm({
resolver: yupResolver(schema),
});

유효성 검사를 Controller에 작성했을 때는 코드도 복잡하고, 코드도 흩어져 있기 때문에 조건을 확인하기 어렵습니다. 하지만, Yup을 사용하면 스키마 객체를 통해 폼의 유효성 검사를 한 곳에서 정의할 수 있으며, React Hook Form과 결합하여 훨씬 더 효율적이고 재사용 가능한 코드를 작성할 수 있습니다.

 

Zod와 비교

Yup과 비슷한 역할을 하는 또 다른 라이브러리로 Zod가 있습니다. 두 라이브러리는 모두 폼 유효성 검사를 위한 스키마 기반 검증 도구이지만, 몇 가지 차이점이 있습니다.

Yup vs Zod 비교 차트

특징 Yup Zod
문법 선언적이고 직관적인 문법 함수형 프로그래밍 스타일에 가까운 문법
TypeScript 지원 기본적으로 타입 지원은 가능하지만, 타입 추론에 한계가 있음 TypeScript와의 통합이 좋음
학습 곡선(러닝 커브) 처음 접하는 개발자도 쉽게 사용할 수 있음 함수형 스타일로 인해 다소 높은 진입장벽

 

마치면서

회사 프로젝트를 진행하면서 Yup을 처음 접하고, 이를 추천하는 글을 작성하려 했습니다. 그런데 공부를 하다 보니 Zod라는 강력한 대안을 알게 되었고, 비교해 보면 Zod가 더 나은 선택처럼 느껴졌습니다. 😅

그렇지만, Yup 은 여전히 직관적인 문법과 다양한 검증 규칙을 제공하여 복잡한 폼 검증을 손쉽게 구현할 수 있는 강력한 도구입니다. 특히 React Hook Form을 처음 접하는 초보자나 간단한 프로젝트에서는 Yup이 더 적합할 수 있습니다. Yup에 익숙해진 후 필요에 따라 Zod로 넘어가는 것도 좋은 선택이 될 것 같습니다!

 

참고자료

- React Hook Form 공식 문서

- Yup 공식 문서

- Zod 공식 문서

끄적끄적 개발자