🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Shadcn Form 완벽 가이드 - 슬라이드 1/13
A

AI Generated

2025. 10. 31. · 23 Views

Shadcn Form 완벽 가이드

Shadcn UI의 Form 컴포넌트와 React Hook Form, Zod를 활용한 고급 폼 구현 방법을 다룹니다. 타입 안전성과 유효성 검증, 에러 핸들링까지 실전에서 바로 사용할 수 있는 패턴을 제공합니다.


카테고리:React
언어:TypeScript
메인 태그:#React
서브 태그:
#Shadcn#ReactHookForm#Zod#FormValidation

들어가며

이 글에서는 Shadcn Form 완벽 가이드에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.

목차

  1. 기본_폼_설정
  2. Form_컴포넌트_구조
  3. 에러_메시지_표시
  4. 복잡한_스키마_검증
  5. 동적_폼_배열
  6. 비동기_검증
  7. FormDescription_활용
  8. 조건부_필드_렌더링
  9. 제출_상태_관리
  10. Select_컴포넌트_통합
  11. 파일_업로드_처리
  12. 전역_에러_처리

1. 기본 폼 설정

개요

Shadcn Form은 React Hook Form과 Zod를 기반으로 타입 안전한 폼을 구축합니다. useForm 훅에 zodResolver를 연결하여 스키마 기반 검증을 수행합니다.

코드 예제

```tsx
const formSchema = z.object({
  email: z.string().email("유효한 이메일을 입력하세요"),
  password: z.string().min(8, "8자 이상 입력하세요"),
})

const form = useForm<z.infer<typeof formSchema>>({
  resolver: zodResolver(formSchema),
  defaultValues: { email: "", password: "" },
})

### 설명

zodResolver가 Zod 스키마를 React Hook Form과 연결하고, z.infer로 타입을 자동 추론하여 타입 안전성을 보장합니다.

---

## 2. Form_컴포넌트_구조

### 개요

Form, FormField, FormItem, FormControl 등 계층적 구조로 폼 UI를 구성합니다. FormField는 Controller를 래핑하여 상태 관리를 단순화합니다.

### 코드 예제

```typescript
```tsx
<Form {...form}>
  <form onSubmit={form.handleSubmit(onSubmit)}>
    <FormField
      control={form.control}
      name="email"
      render={({ field }) => (
        <FormItem>
          <FormLabel>이메일</FormLabel>
          <FormControl>
            <Input {...field} />
          </FormControl>
        </FormItem>
      )}
    />
  </form>
</Form>

### 설명

FormField의 render prop이 field 객체를 제공하며, 이를 Input에 spread하여 value, onChange 등을 자동 연결합니다.

---

## 3. 에러_메시지_표시

### 개요

FormMessage 컴포넌트가 필드별 에러를 자동으로 표시합니다. Zod 스키마의 에러 메시지가 검증 실패 시 렌더링됩니다.

### 코드 예제

```typescript
```tsx
<FormField
  control={form.control}
  name="username"
  render={({ field }) => (
    <FormItem>
      <FormLabel>사용자명</FormLabel>
      <FormControl>
        <Input {...field} />
      </FormControl>
      <FormMessage />
    </FormItem>
  )}
/>

### 설명

FormMessage는 해당 필드의 에러 상태를 자동 감지하여 에러 메시지를 렌더링하며, 별도의 조건부 로직이 필요 없습니다.

---

## 4. 복잡한_스키마_검증

### 개요

Zod의 refine과 superRefine으로 커스텀 검증 로직을 추가할 수 있습니다. 여러 필드 간 관계를 검증할 때 유용합니다.

### 코드 예제

```typescript
```tsx
const schema = z.object({
  password: z.string().min(8),
  confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
  message: "비밀번호가 일치하지 않습니다",
  path: ["confirmPassword"],
})

### 설명

refine 메서드로 두 필드를 비교하고, path 옵션으로 에러를 특정 필드에 연결하여 정확한 위치에 메시지를 표시합니다.

---

## 5. 동적_폼_배열

### 개요

useFieldArray로 동적으로 추가/제거 가능한 폼 필드 배열을 관리합니다. append, remove 메서드로 간편하게 조작할 수 있습니다.

### 코드 예제

```typescript
```tsx
const { fields, append, remove } = useFieldArray({
  control: form.control,
  name: "items",
})

{fields.map((field, index) => (
  <FormField key={field.id} name={`items.${index}.name`}
    render={({ field }) => <Input {...field} />} />
))}
<Button onClick={() => append({ name: "" })}>추가</Button>

### 설명

useFieldArray가 배열 상태를 관리하고, 각 필드는 고유 id로 추적되어 React의 key 최적화를 활용합니다.

---

## 6. 비동기_검증

### 개요

Zod의 .refine 또는 superRefine에서 Promise를 반환하여 API 호출 등 비동기 검증을 수행할 수 있습니다.

### 코드 예제

```typescript
```tsx
const schema = z.object({
  username: z.string().refine(
    async (val) => {
      const res = await fetch(`/api/check?name=${val}`)
      return res.ok
    },
    { message: "이미 사용중인 사용자명입니다" }
  ),
})

### 설명

refine 콜백에서 async 함수를 사용하면 폼 제출 전 비동기 검증이 실행되며, 결과에 따라 에러를 표시합니다.

---

## 7. FormDescription_활용

### 개요

FormDescription으로 필드 설명을 추가하여 사용자 가이드를 제공합니다. 접근성과 UX를 동시에 개선할 수 있습니다.

### 코드 예제

```typescript
```tsx
<FormField
  control={form.control}
  name="bio"
  render={({ field }) => (
    <FormItem>
      <FormLabel>자기소개</FormLabel>
      <FormControl>
        <Textarea {...field} />
      </FormControl>
      <FormDescription>
        200자 이내로 작성해주세요.
      </FormDescription>
    </FormItem>
  )}
/>

### 설명

FormDescription은 FormMessage와 별개로 항상 표시되는 도움말 텍스트로, aria-describedby로 자동 연결됩니다.

---

## 8. 조건부_필드_렌더링

### 개요

watch를 사용하여 특정 필드 값에 따라 다른 필드를 동적으로 표시/숨김 처리할 수 있습니다.

### 코드 예제

```typescript
```tsx
const accountType = form.watch("accountType")

{accountType === "business" && (
  <FormField
    control={form.control}
    name="companyName"
    render={({ field }) => (
      <FormItem>
        <FormLabel>회사명</FormLabel>
        <FormControl><Input {...field} /></FormControl>
      </FormItem>
    )}
  />
)}

### 설명

watch가 필드 값 변경을 구독하여 리렌더링을 트리거하며, 조건부 렌더링된 필드도 자동으로 폼 상태에 통합됩니다.

---

## 9. 제출_상태_관리

### 개요

formState를 통해 제출 중 상태, 에러, 터치 여부 등을 추적하고 UI에 반영할 수 있습니다.

### 코드 예제

```typescript
```tsx
const { isSubmitting, isValid } = form.formState

const onSubmit = async (data: z.infer<typeof schema>) => {
  await fetch("/api/submit", { method: "POST", body: JSON.stringify(data) })
}

<Button type="submit" disabled={isSubmitting || !isValid}>
  {isSubmitting ? "처리중..." : "제출"}
</Button>

### 설명

isSubmitting은 비동기 onSubmit 실행 중 자동으로 true가 되며, isValid는 모든 검증 통과 여부를 실시간 반영합니다.

---

## 10. Select_컴포넌트_통합

### 개요

Shadcn Select를 FormField와 통합할 때 onValueChange를 field.onChange에 연결하여 상태를 동기화합니다.

### 코드 예제

```typescript
```tsx
<FormField
  control={form.control}
  name="country"
  render={({ field }) => (
    <FormItem>
      <FormControl>
        <Select onValueChange={field.onChange} defaultValue={field.value}>
          <SelectTrigger><SelectValue /></SelectTrigger>
          <SelectContent>
            <SelectItem value="kr">한국</SelectItem>
          </SelectContent>
        </Select>
      </FormControl>
    </FormItem>
  )}
/>

### 설명

Select의 onValueChange가 field.onChange와 연결되어 값 변경이 폼 상태에 자동 반영되며, defaultValue로 초기값을 설정합니다.

---

## 11. 파일_업로드_처리

### 개요

Input type="file"을 사용할 때 FileList 타입을 Zod로 검증하고, onChange를 커스터마이징하여 파일 상태를 관리합니다.

### 코드 예제

```typescript
```tsx
const schema = z.object({
  file: z.instanceof(FileList).refine(
    (files) => files.length > 0, "파일을 선택하세요"
  ),
})

<FormControl>
  <Input type="file" {...field} value={field.value?.filename}
    onChange={(e) => field.onChange(e.target.files)} />
</FormControl>

### 설명

FileList 인스턴스를 Zod로 검증하고, onChange에서 e.target.files를 직접 전달하여 파일 객체를 폼 상태에 저장합니다.

---

## 12. 전역_에러_처리

### 개요

setError로 서버 응답 에러를 특정 필드나 root에 수동으로 설정할 수 있습니다. API 에러를 폼 UI에 통합할 때 유용합니다.

### 코드 예제

```typescript
```tsx
const onSubmit = async (data: FormData) => {
  try {
    await api.submit(data)
  } catch (error) {
    form.setError("root", {
      message: "서버 오류가 발생했습니다",
    })
  }
}

{form.formState.errors.root && <p>{form.formState.errors.root.message}</p>}

### 설명

setError의 root 키는 특정 필드가 아닌 폼 전체 에러를 나타내며, formState.errors.root로 접근하여 표시합니다.

---

## 마치며

이번 글에서는 Shadcn Form 완벽 가이드에 대해 알아보았습니다.
총 12가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.

### 관련 태그

#React #Shadcn #ReactHookForm #Zod #FormValidation
#React#Shadcn#ReactHookForm#Zod#FormValidation

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

마이크로서비스 배포 완벽 가이드

Kubernetes를 활용한 마이크로서비스 배포의 핵심 개념부터 실전 운영까지, 초급 개발자도 쉽게 따라할 수 있는 완벽 가이드입니다. 실무에서 바로 적용 가능한 배포 전략과 노하우를 담았습니다.

Application Load Balancer 완벽 가이드

AWS의 Application Load Balancer를 처음 배우는 개발자를 위한 실전 가이드입니다. ALB 생성부터 ECS 연동, 헬스 체크, HTTPS 설정까지 실무에 필요한 모든 내용을 다룹니다. 초급 개발자도 쉽게 따라할 수 있도록 단계별로 설명합니다.

고객 상담 AI 시스템 완벽 구축 가이드

AWS Bedrock Agent와 Knowledge Base를 활용하여 실시간 고객 상담 AI 시스템을 구축하는 방법을 단계별로 학습합니다. RAG 기반 지식 검색부터 Guardrails 안전 장치, 프론트엔드 연동까지 실무에 바로 적용 가능한 완전한 시스템을 만들어봅니다.

에러 처리와 폴백 완벽 가이드

AWS API 호출 시 발생하는 에러를 처리하고 폴백 전략을 구현하는 방법을 다룹니다. ThrottlingException부터 서킷 브레이커 패턴까지, 실전에서 바로 활용할 수 있는 안정적인 에러 처리 기법을 배웁니다.

AWS Bedrock 인용과 출처 표시 완벽 가이드

AWS Bedrock의 Citation 기능을 활용하여 AI 응답의 신뢰도를 높이는 방법을 배웁니다. 출처 추출부터 UI 표시, 검증까지 실무에서 바로 사용할 수 있는 완전한 가이드입니다.

이전4/4
다음