
<input>, <textarea>, <select>)다.setState()에 의해 업데이트된다.function NameForm() {
const [nameValue, setNameValue] = useState('');
const handleChange = (event) => {
setNameValue(event.target.value);
}
const handleSubmit = (event) => {
alert("A name was submitted: " + nameValue);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
/**
* @see
* value 속성: 폼 엘리먼트에 설정되므로 항상 nameValue state로 관리된다. - 신뢰 가능한 단일 출처(Single Source of Truth)
* handleChange: 사용자가 입력할 때 보여지는 값을 업데이트한다.
*/
Name: <input type="text" value={nameValue} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}

function NameForm() {
const inputRef = useRef();
const handleSubmit = (event) => {
alert("A name was submitted: " + inputRef.current.value);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
/**
* @see
* ref 속성: 폼 엘리먼트의 value 속성값을 관리한다. -> 리액트 렌더링 라이프사이클에서 폼 엘리먼트의 value 속성은 DOM의 value로 오버라이드된다. (DOM의 값을 우선시한다.)
* defaultValue 속성: input의 value값을 제어하기 위해 사용한다.
*/
Name: <input defaultValue="Bob" type="text" ref={inputRef} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
value 대신 defaultValue 속성을 지정하여 값을 제어하도록 처리한다.
참고 React Docs - Uncontrolled Components
| 기능 | 제어 컴포넌트 | 비제어 컴포넌트 |
|---|---|---|
일회성 값 검색 (e.g. onSubmit) | ✅ | ✅ |
| 제출 시 유효성 검사 | ✅ | ✅ |
| 실시간 필드 유효성 검사 | ✅ | ❌ |
| 조건 | ✅ | ❌ |
| 조건부 submit 버튼 비활성화 | ✅ | ❌ |
| input 형식 강제화 | ✅ | ❌ |
| 하나의 데이터에 대한 여러 input들 | ✅ | ❌ |
| 동적인 input | ✅ | ❌ |
UI 피드백 측면에서 폼이 굉장히 간단하다면 refs를 사용한 비제어 컴포넌트를 사용해도 문제 없으며, 비제어 컴포넌트를 사용하다 언제든지 제어 컴포넌트로 변경할 수도 있다.
많은 아티클에서의 "setState를 사용하면 안된다", 공식 문서에서의 "ref는 나쁘다".. 등등 다양한 주장들이 있지만, 제어 컴포넌트와 비제어 컴포넌트는 각각의 장점이 있기 때문에 상황에 맞게 사용해야 한다.
참고 Controlled and uncontrolled form inputs in React don't have to be complicated