이미지 업로드 기능을 구현할 때, 사용자가 올바른 파일 형식을 선택했는지 검증하는 것이 중요합니다. 이 과정에서 zod를 활용하면 쉽고 직관적으로 유효성 검사를 수행할 수 있습니다. 이번 글에서는 zod와 react-hook-form을 사용하여 안전한 이미지 업로드 폼을 만드는 방법을 다뤄보겠습니다.
zod는 TypeScript 기반의 스키마 선언 및 유효성 검사 라이브러리로, 직관적인 API를 통해 데이터를 검증할 수 있도록 도와줍니다. 특히 react-hook-form과 함께 사용하면 폼 입력 값을 간편하게 검증할 수 있습니다.
z.infer<typeof schema>를 사용해 타입을 자동으로 추론할 수 있습니다.이미지 업로드 폼에서 중요한 점은 파일이 선택되었는지와 올바른 이미지 형식인지를 검증하는 것입니다. 이를 위해 zod의 custom과 refine을 사용합니다.
import * as z from "zod";
const formSchema = z.object({
image: z
.custom<FileList>()
.refine((files) => files?.length === 1, "이미지를 선택해주세요.")
.refine(
(files) => files?.[0]?.type.startsWith("image/"),
"이미지 파일만 업로드 가능합니다."
),
});
custom<FileList>(): FileList 타입의 입력값을 검증할 준비를 합니다..refine((files) => files?.length === 1, "이미지를 선택해주세요.").refine((files) => files?.[0]?.type.startsWith("image/"), "이미지 파일만 업로드 가능합니다.")image/로 시작하는지 검사하여 이미지 파일 여부를 확인합니다.이제 react-hook-form을 사용하여 zod 스키마를 resolver로 적용합니다. 이를 통해 폼 입력값이 자동으로 검증되며, 오류 발생 시 UI에서 쉽게 처리할 수 있습니다.
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
const form = useForm({
resolver: zodResolver(formSchema),
});
useForm의 resolver에 zodResolver(formSchema)를 전달하면 자동으로 검증이 이루어집니다.react-hook-form이 에러 상태를 감지하고 적절한 메시지를 표시할 수 있습니다.import { useState, useCallback } from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { useDropzone } from "react-dropzone";
import { Button } from "@/components/ui/button";
const formSchema = z.object({
image: z
.custom<FileList>()
.refine((files) => files?.length === 1, "이미지를 선택해주세요.")
.refine(
(files) => files?.[0]?.type.startsWith("image/"),
"이미지 파일만 업로드 가능합니다."
),
});
export function ImageUploadForm() {
const [preview, setPreview] = useState<string | null>(null);
const form = useForm({ resolver: zodResolver(formSchema) });
const onDrop = useCallback((acceptedFiles: File[]) => {
if (acceptedFiles[0]) {
const reader = new FileReader();
reader.onloadend = () => setPreview(reader.result as string);
reader.readAsDataURL(acceptedFiles[0]);
const dataTransfer = new DataTransfer();
dataTransfer.items.add(acceptedFiles[0]);
form.setValue("image", dataTransfer.files);
}
}, [form]);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: { "image/*": [".jpg", ".jpeg", ".png", ".gif", ".webp"] },
multiple: false,
});
return (
<form onSubmit={form.handleSubmit(() => {})}>
<div {...getRootProps()} className="border-2 border-dashed p-6 cursor-pointer">
<input {...getInputProps()} />
{isDragActive ? "이미지를 놓아주세요" : "이미지를 업로드하세요"}
</div>
{preview && <img src={preview} alt="Preview" className="mt-4 max-h-64" />}
<Button type="submit">업로드</Button>
</form>
);
}
이번 글에서는 zod를 활용하여 React에서 안전한 이미지 업로드 폼을 구현하는 방법을 살펴보았습니다. zod를 사용하면 타입 안전성을 유지하면서도 직관적으로 유효성 검사를 적용할 수 있습니다.
react-hook-form과 쉽게 통합 가능