[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-09 21:08:02 +09:00
parent f0befc887a
commit 93ec7e9056
363 changed files with 68333 additions and 64 deletions
@@ -0,0 +1,88 @@
---
id: react-form-state-patterns
title: React Form 상태 패턴
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [react, forms, validation, react-hook-form, vibe-coding]
tech_stack: { language: "TypeScript / React 18+ / react-hook-form / zod", applicable_to: ["Web"] }
applied_in: []
aliases: [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
```tsx
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
```tsx
// '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 으로 전환 요청.
## 🔗 관련 문서
- [[React_Controlled_vs_Uncontrolled]]
- [[Idempotent_Operations]]