React Context API로 전역 상태 관리하기
Context API란?
컴포넌트 트리 깊은 곳에 있는 컴포넌트에 props를 일일이 전달하지 않고 데이터를 공유할 수 있는 방법입니다.
기본 사용법
1. Context 생성
// context/ThemeContext.js
import { createContext, useContext, useState } from 'react'
const ThemeContext = createContext(null)
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light')
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
export function useTheme() {
const context = useContext(ThemeContext)
if (!context) throw new Error('useTheme must be used within ThemeProvider')
return context
}
2. Provider로 감싸기
// App.jsx
import { ThemeProvider } from './context/ThemeContext'
function App() {
return (
<ThemeProvider>
<Header />
<Main />
</ThemeProvider>
)
}
3. 어느 컴포넌트에서나 사용
function Header() {
const { theme, setTheme } = useTheme()
return (
<header className={theme === 'dark' ? 'bg-gray-900' : 'bg-white'}>
<button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
테마 전환
</button>
</header>
)
}
실전 예제 — 인증 Context
// context/AuthContext.js
import { createContext, useContext, useState } from 'react'
const AuthContext = createContext(null)
export function AuthProvider({ children }) {
const [user, setUser] = useState(null)
async function login(email, password) {
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password }),
})
const data = await res.json()
setUser(data.user)
}
function logout() {
setUser(null)
}
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
)
}
export const useAuth = () => useContext(AuthContext)
Context vs Zustand 선택 기준
| 상황 | 선택 |
|---|---|
| 테마, 로케일 등 변경이 적은 데이터 | Context API |
| 자주 변경되는 복잡한 상태 | Zustand / Jotai |
| 서버 데이터 캐싱 | TanStack Query |
| 대규모 앱 전역 상태 | Redux Toolkit |
성능 최적화 — memo와 함께 사용
Context 값이 변경되면 하위 모든 컴포넌트가 리렌더링됩니다. memo로 불필요한 렌더링을 방지합니다.
import { memo } from 'react'
const ExpensiveChild = memo(function ExpensiveChild({ name }) {
return <div>{name}</div>
})