[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
---
|
||||
id: react-controlled-vs-uncontrolled
|
||||
title: Controlled vs Uncontrolled 컴포넌트
|
||||
category: Coding
|
||||
status: draft
|
||||
source_trust_level: B
|
||||
verification_status: conceptual
|
||||
created_at: 2026-05-09
|
||||
updated_at: 2026-05-09
|
||||
tags: [react, forms, state, vibe-coding]
|
||||
tech_stack: { language: "TypeScript / React 18+", applicable_to: ["Web"] }
|
||||
applied_in: []
|
||||
aliases: [defaultValue, value prop, ref, form pattern]
|
||||
---
|
||||
|
||||
# Controlled vs Uncontrolled 컴포넌트
|
||||
|
||||
> "이 input 의 값이 React state 에 사는가, DOM 에 사는가?" 답에 따라 두 패턴. 한 컴포넌트에서 둘 섞으면 사고. **한 가지 결정 후 일관**.
|
||||
|
||||
## 📖 핵심 개념
|
||||
- **Controlled**: `value={state}` + `onChange={setState}`. React 가 단일 진실원.
|
||||
- **Uncontrolled**: `defaultValue` + `ref.current.value`. DOM 이 진실원.
|
||||
|
||||
전환은 비싸다. 한 번 controlled 면 영원히 controlled, 그 반대도. React 가 console warning.
|
||||
|
||||
## 💻 코드 패턴
|
||||
|
||||
```tsx
|
||||
// ✅ Controlled — 검증/변환/즉시 반영 필요
|
||||
function NameInput() {
|
||||
const [name, setName] = useState('');
|
||||
return <input value={name} onChange={e => setName(e.target.value.toUpperCase())} />;
|
||||
}
|
||||
|
||||
// ✅ Uncontrolled — 큰 form, 제출 시점만 값 필요
|
||||
function BigForm() {
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
const onSubmit = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
const data = new FormData(formRef.current!);
|
||||
sendApi(Object.fromEntries(data));
|
||||
};
|
||||
return <form ref={formRef} onSubmit={onSubmit}>
|
||||
<input name="email" defaultValue="" />
|
||||
</form>;
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준
|
||||
| 상황 | Controlled | Uncontrolled |
|
||||
|---|---|---|
|
||||
| 입력마다 검증/변환 | ✅ | ❌ |
|
||||
| 다른 UI 가 동시에 반응 | ✅ | ❌ |
|
||||
| 큰 form, 제출만 중요 | ❌ (재렌더 부하) | ✅ |
|
||||
| 파일 업로드 input | ❌ (보안 제한) | ✅ |
|
||||
| 외부 라이브러리 (date picker) | 라이브러리에 따라 | — |
|
||||
| react-hook-form 사용 | hybrid (ref 기반 + controlled API) | — |
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **value 와 defaultValue 모두 지정**: defaultValue 무시 + warning.
|
||||
- **value=undefined 로 시작 → 나중에 string**: controlled 로 전환 → React warning. 항상 ''.
|
||||
- **controlled 인데 onChange 없음**: read-only 처럼 보이는 잠긴 상태 + warning.
|
||||
- **uncontrolled 에서 매번 ref.current.value 읽기 + state 같이 관리**: 둘 동기 안 맞아 사고.
|
||||
- **숫자 input 을 string state**: parseInt/Number 처리 누락 → NaN 폭발.
|
||||
|
||||
## 🤖 LLM 활용 힌트
|
||||
- form 작성 요청 시 "controlled 또는 react-hook-form 둘 중 하나로 일관" 명시.
|
||||
- LLM이 큰 form 을 모두 controlled 로 만들면 성능 risk → react-hook-form 권유.
|
||||
|
||||
## 🔗 관련 문서
|
||||
- [[React_Form_State_Patterns]]
|
||||
- [[React_Refs_Patterns]]
|
||||
Reference in New Issue
Block a user