React 애플리케이션을 개발하다 보면 여러 컴포넌트 층을 거쳐 props를 전달해야 하는 상황을 마주치게 된다. 이를 Props Drilling이라고 부르며, 코드의 복잡성을 증가시키고 유지보수를 어렵게 만든다. React의 Context API는 이 문제를 우아하게 해결하는 방법이다.
// Props를 여러 단계에 거쳐 전달하는 상황
<GrandParent user={user} />
// → <Parent user={user} />
// → <Child user={user} />
// → <GrandChild user={user} />
각 컴포넌트가 자신이 필요하지 않은 props까지 받아서 전달해야 한다. 이는 코드를 복잡하게 하고 리팩토링을 어렵게 만든다.
Context API를 사용하면 중간 컴포넌트를 거치지 않고 깊은 계층의 컴포넌트에 값을 직접 전달할 수 있다. 세 가지 주요 요소로 구성된다.
import { createContext } from 'react';
const UserContext = createContext();
function App() {
const [user, setUser] = useState({ name: 'John', theme: 'dark' });
return (
<UserContext.Provider value={user}>
<GrandParent />
</UserContext.Provider>
);
}
import { useContext } from 'react';
function GrandChild() {
const user = useContext(UserContext);
return <div>Welcome, {user.name}!</div>;
}
다크 모드와 라이트 모드를 전환하는 기능을 Context API로 구현해보자.
import { createContext, useContext, useState } from 'react';
// 1. Context 생성
const ThemeContext = createContext();
// 2. Provider 컴포넌트 작성
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// 3. Custom Hook 만들기 (선택사항이지만 권장)
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme은 ThemeProvider 내에서만 사용 가능합니다.');
}
return context;
}
// 4. 사용하기
function Header() {
const { theme, toggleTheme } = useTheme();
return (
<header style={{
background: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#000' : '#fff'
}}>
<button onClick={toggleTheme}>
{theme === 'light' ? '🌙 다크 모드' : '☀️ 라이트 모드'}
</button>
</header>
);
}
function App() {
return (
<ThemeProvider>
<Header />
<Main />
<Footer />
</ThemeProvider>
);
}
값의 변경 없이도 리렌더링을 피하려면, Provider의 value를 메모이제이션하는 것이 좋다.
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const value = useMemo(() => ({
theme,
toggleTheme: () => setTheme(prev => prev === 'light' ? 'dark' : 'light')
}), [theme]);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}
또는 상태를 분리하여 자주 변경되는 값과 거의 변경하지 않는 값을 다른 Context로 나누는 것도 효과적이다.
Context API는 React에서 제공하는 강력한 기능으로, Props Drilling을 해결하고 코드의 가독성을 높인다. 적절히 활용하면 중소 규모의 애플리케이션에서 매우 효과적인 상태 관리 도구가 될 수 있다.