Framework && Library/React

[React] Context API 사용이유 및 용도, 유의사항, 예시코드

기록하는 습관. 2025. 1. 7. 15:12

image

image

React의 기본적인 데이터 전달 흐름은 부모 컴포넌트(상위 컴포넌트)에서 자식 컴포넌트(하위 컴포넌트)로 전달합니다. 계층적인 컴포넌트 구조가 있을 때, 가장 하위 레벨의 컴포넌트가장 상위 레벨의 컴포넌트의 데이터 값을 필요로 한다면 이 값을 중간 레벨의 컴포넌트들이 넘겨줘야합니다.


이는 단순히 중간 레벨의 컴포넌트하위 레벨 컴포넌트로 넘겨주는 역할로만 사용된다면 코드의 복잡성을 증가시켜 차후의 유지보수가 어렵게 됩니다. 이를 보완하고자 사용할 수 있는 것이 Context API입니다.



STEP 1. Context API

STEP 1-1. 사용이유 및 용도, 유의사항

Context를 사용하면 기존에 props로 데이터를 전달하는 방법이 아닌 useContext()로 전달받아 하위 컴포넌트에서 사용합니다. 핵심은 Context를 사용하면 전역적으로 데이터를 관리하고 데이터를 공유할 수 있다는 것입니다. 또한 Context API로 만든 컴포넌트 내부에 비즈니스 로직을 포함하여 코드의 응집도를 높일 수 있습니다.


Context API의 대표 주요 용도는 아래와 같습니다.

설명 용도 예시
전역 상태 관리 애플리케이션 전체에서 공유해야 할 데이터를 관리할 때 사용 현재 사용자 정보, 테마, 언어 설정, 인증 상태 등
컴포넌트 트리 간소화 - 부모에서 자식으로 데이터를 단계별로 전달할 필요 없이 필요한 컴포넌트에서 직접 데이터 접근이 가능

- Props drilling 문제를 해결
테마 관리 다크 모드 / 라이트 모드와 같은 UI 테마를 여러 컴포넌트에서 공유해야할 때 유용
다국어 지원 언어 번역과 같은 로컬라이제이션(Localization) 데이터를 Context로 관리할 수 있음
비즈니스 로직 또는 설정 데이터 관리 API, URL, 환경 변수, 공통적으로 사용하는 데이터 형식 등을 Context로 관리

Context를 이용해 모든 상태를 관리하면 유용하겠다는 생각을 할 수 있습니다. 결론적으로는 안됩니다.
불필요하게 많은 상태를 Context로 관리하게 될 경우 코드의 가독성, 성능, 의존성 문제에 악영향을 줄 수 있습니다.

  • 성능문제
    • Context에 저장되어 있는 값이 변경된다면 Context를 사용하는 모든 컴포넌트가 모두 리렌더링 되어 성능문제를 야기 할 수 있습니다. 이를 해결하기 위해서는 Context를 세분화하여 여러 Context로 분리하는 방법, 필요하다면 useMemo를 활용하여 최적화하는 방법이 있습니다.
  • 의존성 문제
    • Context를 사용하는 컴포넌트에서 의존성이 증가되어 유지보수가 어렵게 될 수 있습니다.

"Context는 상태 관리 도구가 아닙니다."

Context는 복잡한 상태 관리를 위해 설계되지 않았습니다. 상태관리는 Redux, Zustand, Recoil과 같은 라이브러리가 더 적합할 수 있고 Context는 간단한 전역 데이터 관리에 적합합니다.



STEP 1-2. 예시코드 + 개념

  • ThemeContext.js
import React, { createContext, useState } from "react";

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

// 2. Context Provider 컴포넌트 생성
function ThemeProvider({ children }) {
    const [theme, setTheme] = useState("light");

    const toggleTheme = () => {
        setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
    };

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

export { ThemeContext, ThemeProvider };

const ThemeContext = createContext();

데이터를 전역적으로 공유하기 위해 Context 객체를 생성합니다.
Context 객체는 createContext()로 만들 수 있습니다.
코드에서는 ThemeContext가 되며 컴포넌트 트리 어디에서든 접근 가능한 테마 관련 데이터를 제공하는 역할을 합니다.


<ThemeContext.Provider value={{ theme, toggleTheme }}>

Provider는 Context 데이터를 제공하는 역할을 합니다.
value 속성을 통해 자식 컴포넌트들이 접근 할 수 있는 데이터를 지정합니다.
코드에서는 theme와 toogleTheme를 공급합니다.


  • ThemedButton.js
// ThemedButton.js
import React, { useContext } from "react";
import { ThemeContext } from "./ThemeContext";

const getStyles = (theme) => ({
    padding: "10px 20px",
    backgroundColor: theme === "light" ? "#ffffff" : "#333333",
    color: theme === "light" ? "#000000" : "#ffffff",
    border: "1px solid #cccccc",
    borderRadius: "5px",
    cursor: "pointer",
});

// Context를 사용하는 하위 컴포넌트
function ThemedButton() {
    // Context에서 필요한 데이터 추출
    const { theme, toggleTheme } = useContext(ThemeContext);

    return (
        <button
            onClick={toggleTheme}
            style={getStyles(theme)}
        >
            현재 테마: {theme} (클릭하여 변경)
        </button>
    );
}

export default ThemedButton;

Context를 사용하기 위해 useContext() Hook을 사용합니다.
위의 코드에서는 useContext()를 사용하여 ThemeContext 값을 직접 가져옵니다.
버튼의 스타일과 동작을 theme에 따라 동적으로 설정하고, 버튼 클릭 시 toggleTheme를 호출하여 테마를 전환합니다.


  • App.js
// App.js
import React from "react";
import { ThemeProvider } from "./ThemeContext";
import ThemedButton from "./ThemedButton";

// 스타일 함수 정의
const getContainerStyles = () => ({
    padding: "20px",
    textAlign: "center",
});

function App() {
    return (
        <ThemeProvider>
            <div style={getContainerStyles()}>
                <h1>React Context API Example</h1>
                <ThemedButton />
            </div>
        </ThemeProvider>
    );
}

export default App;

<ThemeProvider>
    <div style={getContainerStyles()}>
        <h1>React Context API Example</h1>
        <ThemedButton />
    </div>
</ThemeProvider>

ThemeProviderApp 컴포넌트를 감싸 애플리케이션 전체에 전역 상태를 공급합니다. ThemedButtonThemeProvider 내부에 포함된 하위 컴포넌트로서 Context 데이터를 사용합니다. 이때 중요한 것은 ThemeProvider 내부의 엘리먼트 및 컴포넌트는 ThemeProviderchildren으로 사용됩니다.