제어 컴포넌트와 비제어 컴포넌트

Vincent·2023년 5월 15일
0

제어/비제어 컴포넌트란?

  • 제어 컴포넌트: React에 의해 값이 제어되는 폼 엘리먼트
  • 비제어 컴포넌트: React에 의해 값이 제어되지 않는 폼 엘리먼트
    폼 엘리먼트: Form을 구성하는, 사용자 입력을 기반으로 DOM 자체에서 내부 상태를 가지는 DOM 엘리먼트 ex) input, textarea, select

왜 폼 엘리먼트만 제어/비제어로 구분하는가? 🤔

React에서 (폼 엘리먼트가 아닌) 일반적인 DOM 엘리먼트의 경우 React의 state로 상태를 관리하고 그 상태를 바탕으로 UI를 렌더링하는 방식을 따른다.

  1. 컴포넌트 내에서 local state를 직접 관리
  2. 부모로부터 props를 통해 state를 내려받기
  3. Context API, 전역 상태관리 라이브러리 (e.g. redux) 등을 통해 전역 state를 주입받기

반면 폼 엘리먼트는, 사용자 입력을 기반으로 DOM 자체에서 내부 상태를 가진다. 이 상태는 React의 state가 아니라, DOM이 자체적으로 가지는 state이므로 React에 의해 값이 제어되지 않는다.

React에서 이렇게 DOM이 자체적으로 가지는 상태에 접근하고 싶다면, ref를 통해 접근해야 한다. Vanilla js에서 사용했던 방식과 유사한 방식이며, DOM의 값이 "필요할 때만" ref.current를 통해 현재 DOM의 데이터를 참조하는 방식이다.

제어/비제어 컴포넌트의 예시

같은 폼 엘리먼트라도, 제어 컴포넌트 방식으로 다룰 수도 있고 비제어 컴포넌트 방식으로 다룰 수도 있다. 단순히 폼 엘리먼트의 value를 prop으로 관리하도록 하면 그것이 제어 컴포넌트 방식이다.

//제어컴포넌트
function ControlledInput() {
	const [inputValue, setInputValue] = useState("")
	return (
      <>
		<input type="text" value={inputValue} onChange={(e) = setInputValue(e.target.value)} />
		<button onClick={() = console.log (inputValue)}> 
  show value
      </button>
      </>
	)
}
//비제어컴포넌트
function UncontrolledInput() {
	const inputRef = useRef (null)
	return (
      <>
		<input type="text" ref={inputRef} />
		<button onClick={() = console.log (inputRef.current.value)}>
  			show value
			</button>
  	 </>
      )
}
제어 컴포넌트 flow
- 사용자 입력 이벤트 발생
- 이벤트 핸들러에서 setState(newState)
- 수정된 state를 바탕으로 React가 엘리먼트를 리렌더

비제어 컴포넌트 flow
- 사용자 입력 이벤트 발생
- DOM 엘리먼트의 상태 직접 변경

언제 제어 컴포넌트를, 언제 비제어 컴포넌트를 사용해야 하는가?

보다 React스러운 방식은 제어 컴포넌트이다. React 공식 홈페이지에서도 이를 권장하고 있다.

제어 컴포넌트의 경우, react가 상태를 관리하므로 state가 변경될 때마다 그 값을 바탕으로 DOM이 새롭게 렌더링 된다. 즉, React에서는 항상 실시간으로 최신 상태를 유지할 수 있다. 이렇듯 React에서 컴포넌트 상태에 대한 완전한 주도권을 가지고 있기 때문에 세부적인 Form 조작이 편리하다. 예를 들어, value의 length가 5 이상이 되는 시점에 버튼을 표시해준다던가, 입력을 조건부로 제한한다던가 하는 등의 구현을 손쉽게 할 수 있다.

하지만 Form이 간단하고, 실시간으로 이루어져야 하는 작업이 없다면 구태여 제어 컴포넌트를 이용할 필요는 없다. 제어 컴포넌트를 사용하는 것에는 대가가 따르기 때문이다. Form을 제어 컴포넌트로 잘 관리하기 위해서는 state 관리 위치에 대한 고민 & 잦은 리렌더링을 방지하기 위한 성능 최적화가 필요하다.

상태를 어느 레벨에서 관리할 것인가?는 곧 어떤 범위에서 상태를 참조하고 있는가 에 대한 답이라고 할 수 있다. Form의 상태를 넓은 범위에서 참조하고 있다면 그만큼 Form 데이터 업데이트 시 많은 컴포넌트에서 재 렌더링이 발생할 수 있다는 것을 의미한다.

따라서 일반적인 Form의 방식대로 비제어 컴포넌트로 사용하는 것이 더 심플하고 성능이 좋은 방법일 수 있다. 상황에 맞게 비제어/제어 컴포넌트를 사용할 수 있게 도와주는 react-hook-form과 같은 라이브러리들도 존재한다.

profile
Frontend & Artificial Intelligence

0개의 댓글