Files
2nd/10_Wiki/Topics/Coding/React_Form_State_Patterns.md
T
2026-05-09 21:08:02 +09:00

3.1 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
react-form-state-patterns React Form 상태 패턴 Coding draft B conceptual 2026-05-09 2026-05-09
react
forms
validation
react-hook-form
vibe-coding
language applicable_to
TypeScript / React 18+ / react-hook-form / zod
Web
form library
validation schema
dirty fields

React Form 상태 패턴

큰 form 에서 매 keystroke setState 면 재렌더 폭주. react-hook-form (uncontrolled + ref) 또는 Server Action + form data 가 답. 검증은 zod 스키마.

📖 핵심 개념

form 의 어려움: 검증 / dirty 추적 / 제출 / 에러 표시 / async 검증 / 의존 필드. 직접 구현하면 복잡 + 성능 함정.

💻 코드 패턴

1. react-hook-form + zod

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const schema = z.object({
  email: z.string().email(),
  age: z.coerce.number().int().min(13),
});
type FormData = z.infer<typeof schema>;

function SignupForm() {
  const { register, handleSubmit, formState: { errors, isSubmitting } } =
    useForm<FormData>({ resolver: zodResolver(schema) });

  return (
    <form onSubmit={handleSubmit(async data => { await api.signup(data); })}>
      <input {...register('email')} />
      {errors.email && <p>{errors.email.message}</p>}
      <input {...register('age')} type="number" />
      <button disabled={isSubmitting}>제출</button>
    </form>
  );
}

2. Next.js Server Action

// 'use server'
async function signup(formData: FormData) {
  const parsed = schema.safeParse(Object.fromEntries(formData));
  if (!parsed.success) return { error: parsed.error.flatten() };
  await db.users.create(parsed.data);
}

// Client (또는 server-rendered form)
<form action={signup}>...</form>

🤔 의사결정 기준

form 크기 / 복잡도 권장
1~3 input, 검증 단순 useState controlled
5+ input, 다중 검증 react-hook-form + zod
Server-side validation 강제 Server Action + zod (서버에서 재검증 필수)
다단계 wizard react-hook-form + form context, 또는 zustand
동적 필드 추가/제거 useFieldArray

안티패턴

  • 모든 input 에 useState: 매 keystroke 전체 form 재렌더.
  • 클라이언트 검증만 신뢰: 서버에서 반드시 재검증. 클라는 UX, 서버는 진실.
  • 중복 schema (TS interface + 별도 validator): zod 의 z.infer 로 single source.
  • submit 후 input 안 비움: form.reset() 호출.
  • disabled button 만으로 다중 제출 막기: 빠른 더블 클릭에 race. Idempotency key 또는 mutation queue.
  • 에러 메시지를 toast로만: 어떤 필드가 문제인지 보여야 함. 인라인.

🤖 LLM 활용 힌트

  • "react-hook-form + zod 조합으로 작성, 검증은 클라+서버 둘 다" 명시.
  • 큰 form 일 때 LLM이 useState 다발 만들면 react-hook-form 으로 전환 요청.

🔗 관련 문서