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>
ThemeProvider
는 App
컴포넌트를 감싸 애플리케이션 전체에 전역 상태를 공급합니다. ThemedButton
은 ThemeProvider
내부에 포함된 하위 컴포넌트로서 Context 데이터를 사용합니다. 이때 중요한 것은 ThemeProvider
내부의 엘리먼트 및 컴포넌트는 ThemeProvider
의 children
으로 사용됩니다.
'Framework && Library > React' 카테고리의 다른 글
[React] List 및 key의 개념, map()함수, key의 사용목적은 렌더링 효율에 있다. (0) | 2025.01.05 |
---|---|
[React] 클래스형 컴포넌트의 bind() + 대안 (0) | 2025.01.04 |
[React] useEffect() : Side effect 분리 Hook (0) | 2025.01.03 |