React의 제어/비제어 컴포넌트에 대해

cansweep·2022년 8월 21일
2
post-thumbnail

얼마 전 벨로그에서 이 글(useState vs useRef)을 읽었다.
내가 처음 이 글을 보았을 때에는 내용이 추가되기 전이었는데 나랑 같은 고민을 하고 있던 것이 꽤 흥미로웠다.

보통 input 태그를 사용하고 여기 입력된 값을 가져오기 위해 다음과 같이 작성한다.

import { useState } from 'react';

function App() {
  const [value, setValue] = useState("");
  
  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
}

export default App

사용자가 입력창에 입력할 때마다 setValue를 통해 value의 값이 바뀌게 되고 따라서 매 입력마다 리렌더링이 일어나게 된다.

여기서 나는 사용자가 입력한 값의 결과만 알고 싶은데 이 중간 과정에서 리렌더링이 많이 일어나는 것이 불필요한 게 아닐까? 하고 생각했었다.

사실 이 문제에 대한 답은 이미 React 공식문서 내에 있었다.
공식문서를 제대로 읽지 않은 것을 반성하면서 한 번 짚고 넘어가고자 한다.

제어 컴포넌트(Controlled Component)

HTML에서 <input>, <textarea>, <select>와 같은 폼 엘리먼트는 일반적으로 사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트한다.

import { useState } from 'react';

function App() {
  const [value, setValue] = useState("");
  
  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
}

export default App

그러니까, 이 코드같이 사용한다.

React의 State를 신뢰 가능한 단일 출처로 만들어 사용하면 폼을 렌더링하는 React 컴포넌트는 폼에 발생하는 사용자 입력값을 제어한다.

즉, 이러한 방식으로 React에 의해 값이 제어되는 입력 폼 엘리먼트를 제어 컴포넌트(Controlled Component)라고 한다.

비제어 컴포넌트(Uncontrolled Component)

제어 컴포넌트는 데이터를 변경할 수 있는 모든 방법에 대해 이벤트 핸들러를 작성하고 React 컴포넌트를 통해 모든 입력 상태를 연결해야 하기 때문에 이 방법 대신 ref를 사용해 DOM에서 폼 값을 가져올 수 있다.

import { useRef } from 'react';

function App() {
  const ref = useRef(null);
  
  return <input ref={ref} />;
}

export default App

비제어 컴포넌트는 DOM에 신뢰 가능한 출처를 유지하기때문에 React와 non-React 코드를 통합하는 것이 쉬울 수 있다.

결론

대부분의 경우 폼을 구현하는데에는 제어 컴포넌트를 사용하는 것이 좋다.
제어 컴포넌트에서 폼 데이터는 React 컴포넌트에서 다루어지고 비제어 컴포넌트에서 폼 데이터는 DOM 자체에서 다루어지기 때문이다.

값을 다루는 방식을 비교해보자면 제어 컴포넌트는 input과 같은 폼 엘리먼트의 현재 값을 React의 state에 저장하고 비제어 컴포넌트는 ref로 DOM 엘리먼트를 저장하고 DOM 엘리먼트의 속성에 접근해 현재 값을 가져온다.

그러니까, 제어 컴포넌트를 사용해 input과 같은 폼 엘리먼트의 현재 값을 React의 state에 저장함으로써 React가 이 값을 추적하는 것을 용이하게 하며, 항상 입력의 최신 값을 가진다는 것을 보장할 필요가 있기 때문에 제어 컴포넌트를 사용하는 것이 좋다.

관련 링크

React 공식문서 - 제어 컴포넌트
React 공식문서 - 비제어 컴포넌트
Controlled and uncontrolled form inputs in React don't have to be complicated

profile
하고 싶은 건 다 해보자! 를 달고 사는 프론트엔드 개발자입니다.

0개의 댓글