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

김세빈·2025년 4월 23일

프론트엔드

목록 보기
1/3

React Hook Form과 제어·비제어 컴포넌트를 정리합니다

프런트엔드 개발에서 폼을 다루는 방식은 크게 제어 컴포넌트비제어 컴포넌트로 나뉩니다. 두 방식을 정확히 이해하면 성능 최적화와 유지보수 측면에서 큰 도움이 됩니다. 본 글에서는 두 방식의 차이를 설명하고, react-hook-form이 왜 비제어 컴포넌트 방식을 택했는지 살펴봅니다.


제어 컴포넌트는 입력 요소의 값을 React state로 관리합니다. 사용자가 타이핑할 때마다 onChange 이벤트가 호출되어 setState를 통해 값을 업데이트합니다. React는 상태 변화를 감지해 컴포넌트를 다시 렌더링하며, 이 과정에서 UI와 state가 항상 동기화됩니다.

export default function App() {
  const [input, setInput] = useState("");
  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setInput(e.target.value);
  };

  return (
    <div className="App">
      <input value={input} onChange={onChange} />
    </div>
  );
}

위 예시는 사용자가 입력할 때마다 input 상태가 업데이트되며, 컴포넌트가 바로 재렌더링됩니다. 실시간 검증이나 다른 컴포넌트와의 즉각적인 데이터 공유가 필요할 때 유용합니다.


비제어 컴포넌트는 값을 DOM 레퍼런스(ref) 에서 직접 읽습니다. React state를 거치지 않기 때문에 입력 중에는 리렌더링이 발생하지 않습니다. 값이 필요한 시점(예: 제출 버튼 클릭)까지 DOM에 값을 보존하고 있다가, 필요할 때 ref.current.value로 꺼내 사용합니다.

export default function App() {
  const inputRef = useRef<HTMLInputElement>(null);

  const onSubmit = () => {
    if (inputRef.current) {
      console.log(inputRef.current.value);
    }
  };

  return (
    <div className="App">
      <input ref={inputRef} />
      <button type="button" onClick={onSubmit}>
        전송
      </button>
    </div>
  );
}

비제어 방식은 입력 중 불필요한 리렌더링을 최소화해 성능상 장점이 있습니다. 반면 입력 값이 실시간으로 동기화되지 않기 때문에, 입력 값 변화에 즉각 반응해야 하는 상황에서는 적합하지 않을 수 있습니다.


리액트의 대표적인 라이브러리react-hook-form은 기본적으로 비제어 컴포넌트 전략을 채택해 렌더링 수를 최소화합니다. 내부적으로 각 필드를 ref로 추적하므로 입력 이벤트마다 컴포넌트를 재렌더링하지 않습니다. 특히 필드 수가 많은 대형 폼에서 렌더링 비용을 크게 줄여 성능을 향상합니다.

  • 폼 전체가 아닌 필드 단위로 검증을 수행해 불필요한 업데이트를 피합니다.
  • React state에 값을 저장하지 않으므로 메모리 사용량이 감소합니다.

다만 커스텀 UI 라이브러리(MUI, Ant Design 등)의 입력 요소는 내부적으로 state를 관리하기 때문에 제어 컴포넌트로 동작합니다. 이런 컴포넌트와 react-hook-form을 연동하려면 Controller를 사용합니다.

import { Controller } from "react-hook-form";

<Controller
  name="username"
  control={control}
  defaultValue=""
  render={({ field }) => <TextField label="ID" {...field} />}
/>

Controller는 라이브러리 컴포넌트의 valueonChangereact-hook-form에 위임해 제어 방식과 비제어 방식의 장점을 모두 취합니다.


제어 컴포넌트를 사용하면 적합한 상황

  • 입력 값이 다른 컴포넌트로 즉시 전파되어야 할 때 선택합니다.
  • 입력마다 동적 검증이나 자동 완성 등 실시간 반응이 필요한 경우 사용합니다.
  • 복잡하지 않은 작은 폼에서는 구현 단순성을 위해 제어 방식을 써도 무방합니다.

0개의 댓글