제어 컴포넌트는 HTML에서 input, textarea, select와 같은 폼 엘리먼트에서 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트합니다. React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState()에 의해 업데이트됩니다.
React에 의해 값이 제어되는 입력 폼 엘리먼트를 “제어 컴포넌트 (controlled component)“라고 합니다.
제어 컴포넌트에서 input의 value는 React의 state에 의해 결정되는데, 이를 리액트 공식문서에서는 다음과 같이 표현한다. 👇
React state는 신뢰 가능한 단일 출처 (single source of truth)가 됩니다.
export default function App() {
const [input, setInput] = useState("");
const onChange = (e) => {
setInput(e.target.value);
};
return (
<div className="App">
<input onChange={onChange} value={input}/>
</div>
);
}
❗제어 컴포넌트는 사용자 입력 폼에 사용자가 입력을 하면 입력한 값과 저장되는 값이 실시간으로 동기화된다. 따라서 input의 유효성 검사를 할 때 제어 컴포넌트가 용이하다. 항상 최신 값을 유지하는 특성에 따라 현재 input의 value가 유효한지 안 한 지에 대한 검사를 실시간으로 할 수 있다.
❗제어 컴포넌트는 사용자가 입력을 할때마다 리렌더링이 발생한다. 그리고 불필요한 단어를 입력했을 때도 값이 입력되고 state에 반영되는데, 이는 불필요한 리렌더링, 불필요한 api요청으로 인한 자원 낭비 문제로도 연결 될 수 있다.
비제어 컴포넌트는 자바스크립트와 비슷하다. 제어 컴포넌트와는 다르게 ref라는 hook을 이용해서 form에 접근한다.
자바스크립트에서는 submit button을 통해서 form을 제출해야 value 값을 받아올 수 있었는데 그 방식과 다르지 않다. 제어 컴포넌트는 실시간으로 입력하는 데이터가 동기화 된다면 비제어 컴포넌트는 제출버튼을 클릭해야 입력 데이터를 받을 수 있다.
export default function App() {
const inputRef = useRef(); // ref 사용
const onClick = () => {
console.log(inputRef.current.value);
};
return (
<div className="App">
<input ref={inputRef} />
<button type="submit" onClick={onClick}>
전송
</button>
</div>
);
}
JS에서는 querySelector를 통해서 addEventListener를 실행시켰는데, 이와 방식이 비슷하다.
❗제어 컴포넌트와는 다르게 실시간으로 동기화 되지 않는다. 버튼을 클릭해봐야 input에 입력된 값을 받아볼 수 있다.
❗제어 컴포넌트와는 다르게 리렌더링이 계속해서 발생하지는 않지만, 하지만 그만큼 비제어 컴포넌트는 사용자 입력의 가장 최신 값에 접근하기 힘들다는 특성이 있다.
❗ref를 사용하는데 왜 React를 사용해서 제어하지 않는 '비제어 컴포넌트'라고 하는 걸까? 그 이유는, inputRef.current.value 이 코드는 단순히 DOM 엘리먼트에 접근하는 거지 React가 사용된 게 아니다. 그저 일반 DOM API를 사용해서 인풋 DOM 노드의 DOM 노드 값을 설정하는 것이다. 제어 컴포넌트처럼 useState 등 컴포넌트 단위의 상태를 활용해서 state로 값을 관리하지 않기 때문에 비제어 컴포넌트라고 한다.
❗ 공식문서에서는 폼을 구현할 때 제어 컴포넌트를 활용할 것을 권장하고 있다. 그래서 웬만하면 제어 컴포넌트를 사용 하겠지만, 상황에 맞게 사용하면 된다고 생각한다.
실시간으로 유효성 검사가 필요한 경우에는 '제어 컴포넌트'를 사용하는 게 좋을 것이고, 불필요한 재렌더링을 줄이고 싶고 제출 시에만 값이 필요할 때는 '비제어 컴포넌트'를 사용하면 되는 일이니 상황에 맞게 고민해보고 사용하자!
출처