폼 관리는 웹 개발에서 빈번하게 마주지는 과제입니다. 특히 유효성 검사는 사용자 경험과 데이터 무결성을 위해 필수적인 요소입니다. 이번 글에서는 Next.js에서 폼 관리를 간소화 해주는 React Hook Form과 타입스크립트와 함께 사용하기 좋은 스키마 검증 라이브러리인 Zod에 대해 알아보겠습니다.
🪴 React Hook Form이란?
React Hook Form은 리액트 폼을 위한 유연하고 효율적인 라이브러리로, 폼 상태 관리와 유효성 검사를 간소화 합니다. 기존의 Formik, Redux-Form과 같은 라이브러리들과 비교했을 때 다음과 같은 장점이 있습니다:
- 가벼운 용량: 불필요한 리렌더링을 최소화하여 성능이 우수합니다.
- 간결한 코드: Hooks 기반의 API로 직관적인 사용법을 제공합니다.
- 기존 폼 요소와의 통합: 기존 HTML 폼 요소와 쉽게 통합됩니다.
🪴 Zod란?
Zod는 TypeScript에 최적화된 스키마 유효성 검사 라이브러리입니다. 주요 특징으로는:
- 타입 안전성: 스키마 정의에서 TypeScript 타입을 자동으로 추론합니다.
- 선언적 API: 읽기 쉽고 유지보수하기 좋은 API를 제공합니다.
- 복잡한 유효성 검사: 간단한 필드 검증부터 복잡한 관계 검증까지 가능합니다.
🌱 React Hook Form 기본 사용법
React Hook Form의 기본 사용법을 살펴보겠습니다.
"use client";
import { useForm } from "react-hook-form";
import { FormValues } from "./schema";
const HookPage = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>({});
const onSubmit = (data: FormValues) => {
console.log("회원가입 정보:", data);
alert("회원가입이 완료되었습니다!");
};
return (
<form
onSubmit={handleSubmit(onSubmit)}
className="max-w-md mx-auto p-4 space-y-4"
>
<div className="space-y-2">
<label className="block text-sm font-medium">이메일</label>
<input
type="email"
className="w-full p-2 border rounded"
{...register("email", {
required: { value: true, message: "이메일을 입력해주세요!" },
pattern: {
value: /^\S+@\S+$/i,
message: "이메일 형식이 올바르지 않습니다.",
},
})}
/>
{errors.email && (
<div className="text-red-500 text-sm">{errors.email.message}</div>
)}
</div>
<div className="space-y-2">
<label className="block text-sm font-medium">비밀번호</label>
<input
type="password"
className="w-full p-2 border rounded"
{...register("password", {
required: { value: true, message: "비밀번호를 입력해주세요!" },
minLength: {
value: 8,
message: "비밀번호 길이를 8자리 이상 입력해주세요.",
},
})}
/>
{errors.password && (
<div className="text-red-500 text-sm">{errors.password.message}</div>
)}
</div>
<div className="space-y-2">
<label className="block text-sm font-medium">비밀번호 확인</label>
<input
type="password"
className="w-full p-2 border rounded"
{...register("passwordConfirm", {
required: {
value: true,
message: "비밀번호를 다시 한번 입력해주세요!",
},
validate: (value, formValues) =>
value === formValues.password || "비밀번호가 일치하지 않습니다.",
})}
/>
{errors.passwordConfirm && (
<div className="text-red-500 text-sm">
{errors.passwordConfirm.message}
</div>
)}
</div>
<button
type="submit"
className="w-full bg-blue-500 hover:bg-blue-600 text-white p-2 rounded"
>
회원가입
</button>
</form>
);
};
export default HookPage;
useForm에서 가져오는 :
- register: input 요소를 React hook form과 연결시켜 검증 규칙을 적용할 수 있게 하는 메소드
- handleSubmit: form을 submit 했을 때, 실행할 함수.
- formState: { errors }: input 요소 유효성 검사 실패 시 메세지가 담겨질 errors 객체
🌱 Zod를 활용한 스키마 정의
Zod를 사용하여 폼 스키마를 정의하면 유효성 검사 로직을 컴포넌트 외부로 분리할 수 있습니다.
// schema.ts
import { z } from "zod";
export const formSchema = z.object({
email: z
.string()
.min(1, { message: "이메일을 입력해주세요." })
.email({ message: "이메일 형식이 올바르지 않습니다." }),
password: z
.string()
.min(1, { message: "비밀번호를 입력해주세요." })
.min(8, { message: "비밀번호를 8자리 이상 입력해주세요." }),
passwordConfirm: z
.string()
.min(1, { message: "비밀번호를 다시 한번 입력해주세요." })
}).refine((data) => data.password === data.passwordConfirm, {
message: "비밀번호가 일치하지 않습니다.",
path: ["passwordConfirm"] // 오류가 표시될 필드
});
export type FormValues = z.infer<typeof formSchema>;
🌱 React Hook Form과 Zod 통합하기
두 라이브러리를 함께 사용하면 더욱 견고한 폼 유효성 검사 시스템을 구축할 수 있습니다.
"use client";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { formSchema, FormValues } from "./schema";
const ZodLoginForm = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormValues>({
resolver: zodResolver(formSchema),
});
const onSubmit = (data: FormValues) => {
console.log("회원가입 정보:", data);
alert("회원가입이 완료되었습니다!");
};
return (
<form
onSubmit={handleSubmit(onSubmit)}
className="max-w-md mx-auto p-4 space-y-4"
>
<div className="space-y-2">
<label className="block text-sm font-medium">이메일</label>
<input
type="email"
className="w-full p-2 border rounded"
{...register("email")}
/>
{errors.email && (
<div className="text-red-500 text-sm">{errors.email.message}</div>
)}
</div>
<div className="space-y-2">
<label className="block text-sm font-medium">비밀번호</label>
<input
type="password"
className="w-full p-2 border rounded"
{...register("password")}
/>
{errors.password && (
<div className="text-red-500 text-sm">{errors.password.message}</div>
)}
</div>
<div className="space-y-2">
<label className="block text-sm font-medium">비밀번호 확인</label>
<input
type="password"
className="w-full p-2 border rounded"
{...register("passwordConfirm")}
/>
{errors.passwordConfirm && (
<div className="text-red-500 text-sm">
{errors.passwordConfirm.message}
</div>
)}
</div>
<button
type="submit"
className="w-full bg-blue-500 hover:bg-blue-600 text-white p-2 rounded"
>
회원가입
</button>
</form>
);
};
export default ZodLoginForm;
🌲 결론
React Hook Form과 Zod를 함께 사용하면 다음과 같은 이점이 있습니다:
- 타입 안전성: TypeScript와 완벽하게 통합되어 개발 시 오류를 미리 방지할 수 있습니다.
- 코드 분리: 스키마 정의를 별도 파일로 분리하여 재사용성과 유지보수성을 높일 수 있습니다.
- 선언적 유효성 검사: 복잡한 유효성 검사 규칙을 명확하고 간결하게 표현할 수 있습니다.
- 사용자 경험 향상: 즉각적인 피드백으로 사용자가 쉽게 오류를 수정할 수 있습니다.
이 두 라이브러리의 조합은 복잡한 폼 유효성 검사가 필요한 React 애플리케이션에서 매우 효율적인 솔루션을 제공합니다. 특히 TypeScript를 사용하는 프로젝트에서는 개발 생산성을 크게 향상시킬 수 있습니다. 프로젝트에 적용해보시고 폼관리의 복잡성이 얼마나 줄어드는지 경험해보세요!
'인턴' 카테고리의 다른 글
[ Troubleshooting🛠️ ] CORS 문제 해결 (0) | 2025.04.07 |
---|---|
쿠기(Cookie)와 토큰(Token)의 설명 (0) | 2025.04.04 |
[ Troubleshooting🛠️ ] Next.js에서 Tailwind CSS 설치 시 발생하는 오류 해결하기 (0) | 2025.04.02 |
[ Troubleshooting🛠️ ] Next.js 성능 최적화: 클라이언트 컴포넌트 분리를 통한 이미지 초기 로딩 속도 개선 (0) | 2025.04.02 |
[ Troubleshooting🛠️ ] 패키지 매니저 충돌 트러블 슈팅 npm, yarn, pnpm 간의 전환 (2) | 2025.04.01 |