[React] Control Props 패턴 : Controlled vs Uncontrolled

2025. 5. 7. 18:05·Library & Runtime/React

 

🔍 Control Props 패턴이란?

이전 글에서 Compound Component 패턴에 대해 알아봤다.
컴파운드 컴포넌트 패턴은 부모와 자식 컴포넌트가 자연스럽게 협력하는 구조를 만들기 위한 패턴이었다.
 
Control Props 패턴은 컴포넌트가 자체 상태를 가질 수도 있고, 부모가 상태를 제어할 수도 있게 만드는 패턴이다.
input, select, modal, toggle 등 상태를 외부에서 완전히 제어할 수 있게 해야 하는 컴포넌트에서 사용된다.
 

🧩 예제 코드

이전 글에서 활용한 예제 코드를 수정하여 실습해 보자.

  • Toggle.tsx
import { createContext, useContext, useState, ReactNode } from 'react';

type ToggleContextType = {
  on: boolean; // 불 켜짐/꺼짐 상태
  toggle: () => void; // 상태를 바꾸는 함수
};
// context 공간을 만듦
const ToggleContext = createContext<ToggleContextType | null>(null);

type ToggleProps = {
  children: ReactNode;
  on?: boolean; // 외부 상태 (control props)
  onToggle?: () => void; // 외부 toggle 핸들러
};

// 부모 컴포넌트
// 상태를 만들고 자식 컴포넌트에게 context로 전달
const Toggle = ({ children, on: controlledOn, onToggle }: ToggleProps) => {
  const [uncontrolledOn, setUncontrolledOn] = useState(false);

  const isControlled = controlledOn !== undefined;
  const on = isControlled ? controlledOn : uncontrolledOn;

  const toggle = () => {
    if (isControlled) {
      onToggle?.();
    } else {
      setUncontrolledOn(prev => !prev);
    }
  };

  // 자식 컴포넌트들이 context 데이터에 접근 가능하도록 함
  return <ToggleContext.Provider value={{ on, toggle }}>{children}</ToggleContext.Provider>;
};

// 자식 컴포넌트: On
const ToggleOn = ({ children }: { children: ReactNode }) => {
  const context = useContext(ToggleContext); // context 가져옴
  if (!context) throw new Error('Toggle.On must be used within <Toggle>');

  return context.on ? <>{children}</> : null;
};

Toggle.On = ToggleOn;

// 자식 컴포넌트: Off
const ToggleOff = ({ children }: { children: ReactNode }) => {
  const context = useContext(ToggleContext);
  if (!context) throw new Error('Toggle.Off must be used within <Toggle>');

  return !context.on ? <>{children}</> : null;
};

Toggle.Off = ToggleOff;

// 자식 컴포넌트: Button
const ToggleButton = () => {
  const context = useContext(ToggleContext);
  if (!context) throw new Error('Toggle.Button must be used within <Toggle>');

  return <button onClick={context.toggle}>토글 전환</button>;
};

Toggle.Button = ToggleButton;

export default Toggle;
  • ControlledExample.tsx
import { useState } from 'react';
import Toggle from './Toggle';

const ControlledExample = () => {
  const [isOn, setIsOn] = useState(false);

  return (
    <div style={{ padding: 20 }}>
      <h2>Control Props 패턴 실험</h2>
      <Toggle
        on={isOn} // 부모 상태 넘김
        onToggle={() => setIsOn(prev => !prev)} // 부모 상태 제어
      >
        <Toggle.On>🔆 켜짐 (부모 제어)</Toggle.On>
        <Toggle.Off>🌙 꺼짐 (부모 제어)</Toggle.Off>
        <Toggle.Button />
      </Toggle>
    </div>
  );
};

export default ControlledExample;

 

🧩 정리

패턴해결하는 문제상태 관리UI 구조
Compound Component부모-자식 컴포넌트 API 깔끔하게 구성부모 내부에서 관리부모와 자식이 Context로 연결
Control Props상태를 부모가 직접 제어 가능하게 함부모 또는 외부에서 제어상태 제어와 UI 분리

Control Props 패턴은 부모가 상태를 넘기면 내부 상태를 무시하고 부모 상태로 동작하고, 부모가 상태를 넘기지 않으면 내부 상태를 사용한다.
 


 

🕹️ Controlled vs Uncontrolled

타입상태 제어설명
Controlled 부모(외부)가 상태 제어부모가 value와 onChange를 넘김
Uncontrolled 컴포넌트 내부에서 상태 제어부모가 상태 신경 안 씀

 

▶️ Controlled 특징

<input value={text} onChange={(e) => setText(e.target.value)} />
  • 모든 상태를 부모에서 관리 가능하여 상태를 추적할 수 있다
  • 값 변경 시 로직 추가가 가능하여 검증, 포맷팅 등이 가능하다
  • Redux, Form 관리, validation 등 외부 동기화가 가능하다
  • 복잡한 상태 처리에 강하여 대규모 앱에 적합하다

 

▶️ Uncontrolled 특징

<input defaultValue="hello" />
  • 부모가 상태 관리를 안 해도 돼서 사용하기 쉽다
  • value, onChange를 넘기지 않아도 돼서 코드가 짧다
  • 빠르게 구현 가능하여 작은 앱, 빠른 프로토타입에 유리하다
  • 상태가 외부로 퍼지지 않아 부모 리렌더링 영향을 덜 받는다

 
작은 앱/빠른 개발은 Uncontrolled, 대규모 앱/상태 추적/검증 필요는 Controlled를 쓰면 좋다.
 


 

✏️ 결론

Control Props 패턴은 내부적으론 Controlled 방식으로 동작하지만, 사용하는 입장에서는 Uncontrolled인 것처럼 사용할 수 있는 인터페이스를 제공하는 방식인 것 같다.
그래서 실무에서도 이 패턴을 많이 이용하는 것 같다.
초보 사용자도 쉽게 쓰고, 고급 사용자는 완전히 제어하도록 할 수 있기 때문이다.
토글 예제 코드의 경우에는 값(on)이 주어지면 Controlled, 값이 없으면 Uncontrolled를 사용한다.
 
 
디자인패턴들을 실습해 보면서 드는 생각이 처음엔 어떤 디자인 패턴인지 모르고 사용하는 경우가 많은 것 같다.
정처기 공부하면서 디자인 패턴 설명 봤을 때는 추상적이라 잘 와닿지 않아서 뭔지 모르고 외웠었는데, 실습 코드랑 연결해서 보니 이해된다.
심지어 내가 개발할 때 사용해 본 방식인데 그게 어떤 디자인 패턴인지 명칭을 모르고 사용한 경우가 많아 충격이었다.
어댑터, 전략, 옵저버, 싱글톤, 퍼싸드 등.. 내가 이미 알고 있던 것들인데... 정처기 책에서 설명을 봤을 때는 그게 그거인 줄 몰랐다.
아는 게 연결되고 명확해지니까 디자인 패턴 공부 재밌다.

반응형

'Library & Runtime > React' 카테고리의 다른 글

[React] Compound Component 패턴 + Context 이해하기  (0) 2025.05.06
[React] Virtual Scroll(가상 스크롤)로 렌더링 최적화하기 (react-window)  (0) 2025.05.05
[React] 계산/렌더링 최적화: useMemo + React.memo 실험  (0) 2025.05.04
[React] 무거운 연산 최적화 : 일반 계산 vs useMemo  (0) 2025.05.03
'Library & Runtime/React' 카테고리의 다른 글
  • [React] Compound Component 패턴 + Context 이해하기
  • [React] Virtual Scroll(가상 스크롤)로 렌더링 최적화하기 (react-window)
  • [React] 계산/렌더링 최적화: useMemo + React.memo 실험
  • [React] 무거운 연산 최적화 : 일반 계산 vs useMemo
올콩
올콩
콩 심은 데 콩 난다
  • 올콩
    콩스토리
    올콩
  • 전체
    오늘
    어제
    • 분류 전체보기 (147)
      • SSAFY (10)
      • Algorithm (73)
        • 이론 (5)
        • 백준 (BOJ) (67)
        • 프로그래머스 (1)
      • Language (9)
        • JavaScript (0)
        • TypeScript (0)
        • Java (9)
        • Python (0)
      • Library & Runtime (15)
        • React (13)
        • Node.js (2)
      • Framework (9)
        • 이론 (2)
        • Next.js (3)
        • Vue (4)
      • DevOps (3)
        • Git (3)
      • WEB (18)
        • HTML (9)
        • error (7)
        • etc (2)
      • Computer (5)
        • 자격증 (2)
        • tip (2)
        • etc (1)
      • CS (5)
        • Network (1)
        • Blockchain (4)
  • 블로그 메뉴

    • GitHub
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    vue
    Algorithm
    재귀
    Java
    딕셔너리
    SSAFY
    강의
    github
    html5
    누적합
    Error
    dfs
    렌더링최적화
    블록체인
    DP
    백준
    싸피
    카카오맵
    자바
    Next.js
    SSAFYcial
    파이썬
    해시
    kakaomap
    티스토리챌린지
    우선순위큐
    bfs
    알고리즘
    React
    오블완
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
올콩
[React] Control Props 패턴 : Controlled vs Uncontrolled
상단으로

티스토리툴바