Conceptly
← 전체 목록
⌨️

Controlled Components

상호작용입력 요소의 현재 값을 React state가 단일 기준으로 관리하는 패턴

Controlled Components는 input, textarea, select 같은 폼 요소의 현재 값을 React state가 관리하는 패턴입니다. 사용자가 입력하면 onChange가 state를 바꾸고, 그 state가 다시 value나 checked로 입력 요소에 주입됩니다.

아키텍처 다이어그램

📊 데이터 흐름 다이어그램

점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다

왜 필요한가요?

브라우저 입력 요소는 기본적으로 자신만의 내부 상태를 갖습니다. 이 값을 React가 따로 모르고 있으면, 검증 결과 표시, 버튼 활성화 제어, 다른 UI와의 동기화 같은 작업이 바로 어려워집니다. 폼 값의 진짜 기준이 DOM인지 React state인지 갈라지면 디버깅도 까다로워집니다.

왜 이런 방식이 등장했나요?

전통적인 폼 처리는 제출 시점에 DOM에서 값을 한꺼번에 읽는 방식이 흔했습니다. 하지만 현대 프런트엔드는 입력 중 실시간 검증, 즉시 필터링, 여러 필드 간 의존 관계를 자주 다룹니다. 이런 압력 때문에 입력값을 애플리케이션 상태 흐름 안으로 끌어들이는 controlled 패턴이 널리 쓰이게 됐습니다.

내부적으로 어떻게 동작하나요?

사용자가 입력하면 onChange 핸들러가 새 값을 읽고 state를 갱신합니다. 다음 렌더에서 state의 현재 값이 다시 input의 value나 checked로 들어가므로, 화면에 보이는 입력값과 React state가 항상 같은 기준을 공유합니다. 이 루프 덕분에 입력값을 다른 UI와 쉽게 연결할 수 있습니다.

코드로 보면

입력값과 버튼 상태를 같은 state 기준으로 묶기

import { useState } from "react";

export function InviteForm() {
  const [email, setEmail] = useState("");

  return (
    <>
      <input
        value={email}
        onChange={(event) => setEmail(event.target.value)}
        placeholder="name@example.com"
      />
      <button disabled={email.trim() === ""}>초대 보내기</button>
    </>
  );
}

입력 요소와 버튼 활성화 조건이 같은 state를 바라보므로, 폼의 현재 상태를 React가 한 기준으로 관리하게 됩니다.

체크박스도 checked를 state에서 다시 공급합니다

import { useState } from "react";

export function TermsField() {
  const [agreed, setAgreed] = useState(false);

  return (
    <>
      <label>
        <input
          type="checkbox"
          checked={agreed}
          onChange={(event) => setAgreed(event.target.checked)}
        />
        약관에 동의합니다
      </label>
      <button disabled={!agreed}>계속</button>
    </>
  );
}

텍스트 입력뿐 아니라 체크박스도 브라우저가 들고 있는 값이 아니라 React state를 단일 기준으로 삼는다는 점이 controlled pattern의 핵심입니다.

경계와 구분

Controlled components는 state를 사용하는 폼 패턴이고, ref 기반 접근은 DOM에 들어 있는 현재 값을 필요할 때 직접 읽는 쪽에 가깝습니다. 또한 일반 이벤트 핸들링이 모든 상호작용을 다루는 넓은 개념이라면, controlled pattern은 입력 이벤트를 state와 연결한 특화 구조입니다.

언제 쓰나요?

실무에서는 검색 입력 debounce, 비밀번호 확인, 여러 필드 조합으로 버튼 활성화, 입력값 마스킹 같은 장면에서 controlled pattern이 특히 강합니다. 다만 매우 큰 폼에서 모든 입력을 상위 state 하나로 몰면 재렌더 부담이 커질 수 있으므로, 필드 경계와 상태 위치를 함께 설계해야 합니다.

검색창, 로그인 폼, 설정 화면 입력 제어입력값 검증과 에러 메시지 즉시 표시입력에 따라 버튼 활성화 여부 변경다른 컴포넌트와 폼 값을 동시에 동기화