React 프로젝트를 진행하다 보면 “전역 상태 관리” 문제가 등장한다. 이때 자주 쓰이는 도구가 React Context API와 Redux이다. 이번 글에서는 두 가지를 비교하고, 사용 목적과 실무 적용 방법까지 구체적으로 다루어본다.
1. React Context API
Context API는 단순 전역 상태를 공유할 때 사용한다. 예를 들어 테마(theme), 로그인 정보, 언어 설정 등, 앱 전반에서 소규모 상태를 공유할 때 적합하다.
특징
- React 내장 기능이므로 별도 라이브러리 설치가 필요 없다.
- Provider + useContext 구조로 쉽게 구현 가능하다.
- 상태가 변경되면, 해당 Provider 하위의 모든 컴포넌트가 리렌더링될 수 있어 성능 최적화가 필요하다. (React.memo, useMemo 등 활용)
사용 시기
- 상태가 단순하고, 공유 범위가 한정적일 때
- 소규모 프로젝트나 특정 컴포넌트 계층에서 상태 공유가 필요할 때
예시 코드
const ThemeContext = React.createContext({ theme: "light", toggle: () => {} });
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = React.useState("light");
const toggle = () => setTheme(prev => (prev === "light" ? "dark" : "light"));
return (
<ThemeContext.Provider value={{ theme, toggle }}>
{children}
</ThemeContext.Provider>
);
}
// 사용 예시
const { theme, toggle } = React.useContext(ThemeContext);
2. Redux
Redux는 복잡한 상태를 중앙에서 예측 가능하게 관리하고, 여러 컴포넌트에서 공유할 때 사용한다. 예: API 데이터, 인증 상태, 장바구니, 모달 상태 등.
특징
- Store + Action + Reducer 구조로 중앙 집중식 상태 관리
- Store — 전역 상태를 보관하는 단 하나의 저장소
- Action — "무슨 일이 일어났는가"를 설명하는 객체
- Reducer — Action을 받아 새 상태를 계산하는 순수 함수
- 미들웨어 활용 가능 (Redux Thunk, Saga) → 비동기 처리, 로깅, 상태 추적 가능
- DevTools 지원 → 상태 변화를 시각적으로 추적 가능
사용 시기
- 앱 규모가 중~대형이고 상태가 복잡할 때
- 상태 변경 로직을 명확히 분리하고 추적하고 싶을 때
예시 코드
const counterSlice = createSlice({
name: "counter",
initialState: { value: 0 },
reducers: {
// ✅ REDUCER — Action을 받아 state 계산
increment: state => { state.value += 1 },
decrement: state => { state.value -= 1 }
}
});
// ✅ ACTION — dispatch할 수 있는 함수 (내부적으로 { type: 'counter/increment' } 생성)
export const { increment, decrement } = counterSlice.actions;
// ✅ STORE — 전역 상태 저장소
export const store = configureStore({
reducer: { counter: counterSlice.reducer }
});
// 사용
dispatch(increment()); // ACTION 발행 → REDUCER 실행 → STORE 업데이트
3. Context API vs Redux: 핵심 차이
| 항목 | React Context API | Redux |
| 규모/복잡도 | 소규모, 단순 상태 | 중~대규모, 복잡한 상태 |
| 구조 | Provider + useContext | Store + Action + Reducer, 미들웨어 활용 가능 |
| 성능 | 상태 변경 시 하위 컴포넌트 전체 리렌더링 주의 | selector, memoization 등으로 최적화 가능 |
| 장점 | 가볍고 단순, 설치 필요 없음 | 상태 추적, 테스트, 확장성 용이 |
| 단점 | 큰 앱에서는 성능 저하 가능 | 러닝 커브, 보일러플레이트 코드 존재 |
4. 실무 활용 팁
- *Context + useReducer를 활용하면 Redux 없이도 간단한 중앙 집중식 패턴 구현 가능
- 작은 프로젝트나 특정 영역 상태 관리에는 Context API 추천
- 상태가 많고, 복잡하며, 여러 컴포넌트에서 공유된다면 Redux가 적합
- Redux DevTools를 활용하면 상태 변화를 추적하고 디버깅하기 쉬움
*Context + useReducer를 활용하면 Redux 없이도 간단한 중앙 집중식 패턴 구현 가능
// 1. Action 타입 정의
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
// 2. Reducer
function counterReducer(state, action) {
switch (action.type) {
case INCREMENT: return { count: state.count + 1 };
case DECREMENT: return { count: state.count - 1 };
default: return state;
}
}
// 3. Context 생성
const CounterContext = createContext();
// 4. Provider — Store 역할
function CounterProvider({ children }) {
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
return (
<CounterContext.Provider value={{ state, dispatch }}>
{children}
</CounterContext.Provider>
);
}
// 5. 어디서든 사용
function Counter() {
const { state, dispatch } = useContext(CounterContext);
return (
<div>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: INCREMENT })}>+</button>
<button onClick={() => dispatch({ type: DECREMENT })}>-</button>
</div>
);
}
// 6. App에 Provider 감싸기
function App() {
return (
<CounterProvider>
<Counter />
</CounterProvider>
);
}
Redux와 1:1 대응
| Redux | Context + useReducer |
| store | CounterProvider 내부 state |
| action | dispatch({ type: INCREMENT }) |
| reducer | counterReducer |
| useSelector | useContext(CounterContext).state |
| useDispatch | useContext(CounterContext).dispatch |
5. 결론
React 프로젝트에서 전역 상태 관리 도구를 선택할 때는 앱 규모, 상태 복잡도, 성능 고려가 핵심이다.
- 단순, 한정적 상태 → Context API
- 복잡, 공유 범위 넓은 상태 → Redux
실무에서는 이 두 가지를 조합하거나, Context + Redux-lite 패턴을 적용하기도 한다.
'Frontend > React' 카테고리의 다른 글
| useEffect vs useLayoutEffect (0) | 2025.10.27 |
|---|---|
| 상태(stateful) & 비상태(stateless) 컴포넌트 (0) | 2025.10.25 |
| React에서 비동기 처리 최적화하기 (0) | 2025.10.25 |
| useRef 자세히 알아보기 (0) | 2025.10.24 |
| useEffect의 cleanup 함수 알아보기 (0) | 2025.10.24 |