리액트/기초

✨ React Context : createContext, Provider, useContext란?

lamarcK 2025. 4. 20. 09:51

React Context는 컴포넌트 트리를 통해 데이터를 직접 전달할 수 있는 시스템이다. props drilling 문제를 해결하기 위한 React의 내장 기능이다.

택배 시스템에 비유하면 다음과 같다.

  • createContext = 택배 회사 설립
  • Provider = 물품을 포장하고 배송을 시작하는 지점
  • useContext = 택배 물품을 수령하는 곳

주요 구성 요소

1. createContext()

Context 객체를 생성하는 함수

const MessageContext = React.createContext();

2. Context.Provider

생성된 Context를 통해 데이터를 제공하는 컴포넌트

function App() {
  return (
    <MessageContext.Provider value="Hello">
      <ChildComponent />
    </MessageContext.Provider>
  );
}

3. useContext()

Context의 값을 사용하는 Hook

function ChildComponent() {
  const message = useContext(MessageContext);
  return <div>{message}</div>;
}

실제 사용 예시

// 1. Context 생성
const ThemeContext = React.createContext();

// 2. Provider로 값 제공
function App() {
  const theme = {
    dark: {
      background: 'black',
      color: 'white'
    }
  };

  return (
    <ThemeContext.Provider value={theme}>
      <Header />
      <MainContent />
    </ThemeContext.Provider>
  );
}

// 3. Context 값 사용
function Header() {
  const theme = useContext(ThemeContext);
  return (
    <header style={theme.dark}>
      헤더
    </header>
  );
}

주요 사용 사례

  1. 전역 테마 관리 (다크모드/라이트모드 전환, UI 색상 테마)
  2. 사용자 인증 정보 (로그인 상태, 사용자 권한, 토큰 관리)
  3. 언어 설정 (다국어 지원, i18n 설정, 지역화)
  4. 전역 상태 관리 (장바구니 정보, 알림 메시지, 사이드바 상태)
  5. 환경 설정 (앱 설정, 사용자 기본 설정)
  6. API 클라이언트 공유 (axios 인스턴스, API 엔드포인트)
  7. 라우터 정보 (현재 경로, 네비게이션 상태)
  8. 미디어 쿼리 정보 (반응형 디자인 상태, 화면 크기)
  9. 폼 컨텍스트 (폼 유효성 검사, 폼 상태 관리)
  10. 모달/팝업 관리 (전역 모달 상태, 알림창 관리)

장점

  1. Props Drilling 방지
    • Props Drilling : 상위 컴포넌트의 데이터를 하위 컴포넌트로 전달하기 위해 중간 컴포넌트들을 거쳐가는 현상
    • 프롭스를 특정 컴포넌트에 직접적으로 전달하지 못하고 상속에 상속을 거쳐서 정보를 전달하는 경우 발생
  2. 컴포넌트 간 데이터 공유 용이
    • 이중 상속, 중첩 상속을 하지 않고 다양한 컴포넌트가 데이터를 받아다 쓸 수 있다.
      **기존 Props 방식
      function App() {
        const data = "공유 데이터";
        return (
          <div>
            <A data={data} />
            <B data={data} />
            <C>
              <D data={data} />
            </C>
          </div>
        );
      }
      **Context 방식
      const DataContext = createContext();
      
      function App() {
        const data = "공유 데이터";
        return (
          <DataContext.Provider value={data}>
            <A />  {/* props 전달 불필요 */}
            <B />  {/* 직접 접근 가능 */}
            <C>
              <D /> {/* 중첩된 컴포넌트도 바로 접근 */}
            </C>
          </DataContext.Provider>
        );
      }
      
      // 어떤 컴포넌트에서든 바로 사용 가능
      function D() {
        const data = useContext(DataContext);
        return <div>{data}</div>;
      }
  3. 전역 상태 관리 가능
    • Provider로 감싼 컴포넌트들은 createContext()를 만든 컴포넌트에서 제공한 정보에 UserContext로 접근이 가능하다.
      // UserContext.js
      const UserContext = createContext();  // Context 생성
      
      // App.js
      function App() {
        const userInfo = {    // Provider가 제공할 정보
          name: "Kim",
          age: 25
        };
      
        return (
          <UserContext.Provider value={userInfo}>
            <Header />      {/* userInfo 접근 가능 */}
            <MainContent /> {/* userInfo 접근 가능 */}
            <Footer />      {/* userInfo 접근 가능 */}
          </UserContext.Provider>
        );
      }
      
      // 어떤 하위 컴포넌트든 접근 가능
      function Header() {
        const userInfo = useContext(UserContext);
        return <div>{userInfo.name}</div>;
      }

주의사항

  1. 과도한 사용 지양
  2. 성능 영향 고려
  3. 컴포넌트 재사용성 감소 가능성

권장 사용 패턴

  1. 전역적으로 필요한 데이터에만 사용
  2. 변경이 적은 데이터에 적합
  3. 필요한 범위만큼만 Provider 적용