프로그래밍/ReactJS

React Context API: Prop Drilling 없는 상태 관리의 마법

shimdh 2025. 10. 15. 11:23
728x90

React 애플리케이션을 개발하다 보면, 컴포넌트 트리가 깊어질수록 데이터를 하위 컴포넌트로 전달하는 일이 잦아집니다. 이때 'prop drilling'이라는 골칫덩이가 등장하죠. 이는 필요한 데이터를 최종 목적지까지 전달하기 위해 중간 컴포넌트들이 불필요하게 props를 넘겨야 하는 상황을 말합니다. 결과적으로 코드가 복잡해지고, 유지보수가 어려워지며, 개발 효율이 떨어집니다. 하지만 걱정할 필요 없습니다! React의 Context API가 이 문제를 마법처럼 해결해줍니다. Context API는 전역 상태를 효율적으로 관리하며, prop drilling 없이 컴포넌트 간 데이터 공유를 가능하게 해줍니다.

이 글에서는 Context API의 필요성부터 생성·사용 방법, 그리고 실용적인 테마 전환 예시까지 단계별로 알아보겠습니다. React 개발자라면 필수로 익혀야 할 도구예요!

728x90

Context API, 왜 필요한가요?

Context API는 컴포넌트 트리를 따라 props를 일일이 전달하지 않고도 여러 컴포넌트에서 값을 공유할 수 있게 해줍니다. 특히 애플리케이션 전반에서 공통으로 사용되는 '전역 데이터'—예를 들어 사용자 인증 상태, 테마 설정, 언어 설정—를 다룰 때 빛을 발휘합니다.

  • Prop Drilling 피하기: 중간 컴포넌트가 관심 없는 데이터를 전달할 필요가 없어집니다.
  • 코드 가독성 향상: 상태 관리가 중앙화되어 유지보수가 쉬워집니다.
  • 성능 최적화: 불필요한 리렌더링을 줄일 수 있습니다.

대규모 앱에서 Redux나 MobX 같은 외부 라이브러리를 도입하기 전에, Context API부터 시도해보세요. 가볍고 React 내장 기능이라 학습 곡선도 완만합니다.

Context 생성부터 사용까지: 단계별 가이드

React에서 Context를 효과적으로 사용하는 방법을 단계별로 따라가 보겠습니다. 간단한 예시로 문자열 상태를 공유하는 컨텍스트를 만들어 보죠.

1. createContext 임포트

먼저 React에서 createContext 함수를 가져옵니다.

import React, { createContext } from 'react';

2. Context 정의

createContext()를 호출해 컨텍스트 객체를 생성합니다. 기본값(defaultValue)을 지정하면 Provider가 없을 때 유용합니다.

const MyContext = createContext('기본 값');

3. Provider 컴포넌트 생성

Provider는 컨텍스트 값을 제공하는 역할을 합니다. useState로 상태를 관리하고, value prop으로 자식 컴포넌트에 전달합니다.

import React, { useState } from 'react';

const MyProvider = ({ children }) => {
    const [value, setValue] = useState('초기 값');

    return (
        <MyContext.Provider value={{ value, setValue }}>
            {children}
        </MyContext.Provider>
    );
};

4. 애플리케이션을 Provider로 감싸기

앱의 최상위 또는 특정 섹션을 Provider로 감쌉니다. 이렇게 하면 하위 컴포넌트들이 컨텍스트에 접근할 수 있습니다.

const App = () => (
    <MyProvider>
        <ComponentA />
        <ComponentB />
    </MyProvider>
);

5. Context 값 사용

자식 컴포넌트에서 값을 소비합니다. 현대적인 함수형 컴포넌트라면 useContext 훅을 추천합니다.

useContext 훅 사용 (권장)

import React, { useContext } from 'react';

const ComponentB = () => {
    const { value, setValue } = useContext(MyContext);

    return (
        <div>
            <p>현재 값: {value}</p>
            <button onClick={() => setValue('새로운 값')}>값 변경</button>
        </div>
    );
};

Consumer 사용 (클래스형 컴포넌트 또는 레거시)

특정 상황에서 Consumer를 사용할 수 있습니다.

import React from 'react';

const ComponentC = () => (
    <MyContext.Consumer>
        {({ value }) => <h1>{value}</h1>}
    </MyContext.Consumer>
);

이 단계들을 따르면 prop drilling 없이 깊은 컴포넌트 트리에서도 상태를 공유할 수 있습니다!

실용적인 예시: 테마 전환 기능 구현하기

이론만으로는 부족하죠? Context API로 라이트/다크 테마 전환 기능을 구현해 보겠습니다. 이 예시는 실제 프로젝트에서 바로 적용할 수 있도록 완성했습니다.

1. 테마 Context 생성

import React, { createContext } from 'react';

const ThemeContext = createContext('light'); // 기본 테마: light

2. 테마 Provider 컴포넌트

useState로 테마 상태를 관리합니다.

import React, { useState } from 'react';

const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState('light');

    return (
        <ThemeContext.Provider value={{ theme, setTheme }}>
            {children}
        </ThemeContext.Provider>
    );
};

3. 앱 컴포넌트 설정

앱을 Provider로 감쌉니다.

import React from 'react';

const App = () => (
    <ThemeProvider>
        <Toolbar />
    </ThemeProvider>
);

4. Toolbar 및 테마를 사용하는 컴포넌트

Toolbar 안에 중첩된 ThemedButton에서 컨텍스트를 사용합니다. 버튼 스타일이 테마에 따라 동적으로 변합니다.

import React, { useContext } from 'react';

const Toolbar = () => {
    return (
        <div>
            <ThemedButton />
        </div>
    );
};

const ThemedButton = () => {
    const { theme, setTheme } = useContext(ThemeContext);

    const buttonStyle = {
        backgroundColor: theme === 'dark' ? '#333' : '#FFF',
        color: theme === 'dark' ? '#FFF' : '#000',
        padding: '10px 20px',
        border: '1px solid #ccc',
        margin: '5px'
    };

    return (
        <>
            <button style={buttonStyle}>
                현재 테마: {theme}
            </button>
            <button 
                style={buttonStyle}
                onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
            >
                테마 토글
            </button>
        </>
    );
};

이 예시에서 ThemedButton은 Provider로부터 직접 테마 값을 가져와 스타일을 적용합니다. props를 여러 계층으로 전달할 필요 없이 간단하죠? 실제 앱에서는 CSS-in-JS 라이브러리(styled-components 등)와 결합하면 더 세련되게 구현할 수 있습니다.

테마 전환 예시 이미지


(이미지: 라이트와 다크 테마가 전환되는 버튼 예시)

결론

React Context API는 중첩된 컴포넌트 간 공유 상태를 효율적으로 관리하며, prop drilling의 번거로움을 없애줍니다. 대규모 애플리케이션에서 유지보수성과 가독성을 높이는 데 필수적입니다. Provider로 앱을 감싸고 useContext를 활용하는 간단한 실천만으로도 큰 변화를 느낄 수 있어요.

728x90