일상이 개발
React 상태 관리 완전 정복: Context, Zustand, Redux 비교와 선택 가이드
디어노미
2025. 4. 7. 22:07
반응형
⚙️ React 상태 관리 제대로 설계하기
Context vs Zustand vs Redux 실전 비교 가이드
React로 앱을 개발하다 보면 결국 만나게 되는 고민,
- “이 상태는 어디서 관리해야 할까?”
- “전역 상태 써야 할까? 아니면 컴포넌트 내에서 충분할까?”
그리고 이어지는 고민...
Context? Redux? Zustand? 뭐가 가장 좋지?
이번 글에서는 React 상태 관리의 전반적인 구조 설계 방법과 함께,
Context, Zustand, Redux의 차이점, 그리고 상황에 맞는 선택 가이드를 실전 예제와 함께 소개할게요.
🧠 상태 관리란 무엇인가?
React의 상태(state)는 컴포넌트 내부에서 변화하는 데이터를 의미합니다.
예를 들어 입력 필드, 체크박스 상태, 페이지 전환 상태, API 결과 등.
React는 기본적으로 상태를 위에서 아래로 전달(props) 하는 구조이기 때문에,
공유가 필요한 상태가 생기면 전역 상태 관리의 필요성이 생기죠.
🎯 상태 관리 어떻게 나눌까?
우선 상태를 아래처럼 나눠서 설계해보는 게 중요합니다.
구분 | 설명 | 예시 |
---|---|---|
로컬 상태 | 특정 컴포넌트 내부에서만 사용하는 상태 | 입력창 텍스트, 탭 선택 상태 |
전역 상태 | 여러 컴포넌트가 공유하고, 앱 전체 흐름에 영향 | 로그인 정보, 테마, 장바구니 목록 |
📌 전역 상태는 꼭 필요할 때만 도입!
너무 많은 상태를 전역으로 올리면 오히려 복잡도가 증가합니다.
⚔️ 상태 관리 도구 3대장 비교
Context, Zustand, Redux를 하나씩 비교해볼게요.
1. ✅ Context API
React에 기본 내장된 상태 공유 도구.Provider
로 하위 트리에 상태를 전달합니다.
const ThemeContext = createContext();
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Layout />
</ThemeContext.Provider>
);
}
function Header() {
const { theme } = useContext(ThemeContext);
return <h1>현재 테마: {theme}</h1>;
}
✅ 장점
- 외부 라이브러리 없이 사용 가능
- 간단한 전역 상태에 적합 (토글, 언어, 테마 등)
- TypeScript와도 잘 어울림
❌ 단점
- 상태가 바뀌면 모든 하위 컴포넌트 리렌더링
- 복잡한 상태 구조에서는 성능 이슈 발생 가능
2. ⚡ Zustand
가볍고 직관적인 상태 관리 라이브러리.
Redux처럼 store 개념이 있지만 훨씬 간단합니다.
npm install zustand
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 }))
}));
function Counter() {
const { count, increase } = useStore();
return <button onClick={increase}>클릭 수: {count}</button>;
}
✅ 장점
- 필요한 상태만 구독 (리렌더링 분리 가능)
- 로컬처럼 전역 상태를 간단하게 사용
- Redux보다 코드가 훨씬 짧고 간결
- 비동기, 미들웨어 확장 지원
❌ 단점
- DevTools 기능은 Redux보다 부족
- 복잡한 상태 추적/히스토리에는 다소 불리
💡 로직 공유가 많은 앱에서 Context보다 강력한 대안!
3. 🏢 Redux (with Toolkit)
오래된 강자. 대규모 앱에서 여전히 강력한 도구입니다.
npm install @reduxjs/toolkit react-redux
// counterSlice.js
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increase: (state) => { state.value += 1 }
}
});
export const { increase } = counterSlice.actions;
export default counterSlice.reducer;
// store.js
const store = configureStore({
reducer: {
counter: counterReducer
}
});
// Component
function Counter() {
const count = useSelector((state) => state.counter.value);
const dispatch = useDispatch();
return (
<button onClick={() => dispatch(increase())}>
Redux: {count}
</button>
);
}
✅ 장점
- 상태 흐름이 예측 가능
- DevTools 완비 (타임라인, 추적 등)
- 미들웨어 확장 가능 (Thunk, Saga)
❌ 단점
- 초기 세팅이 복잡
- 코드가 장황해질 수 있음
💡 어떤 상태 관리 도구를 써야 할까?
상황 | 추천 도구 | 이유 |
---|---|---|
단순 전역 값 (테마, 언어 등) | Context | 내장 도구로 충분 |
로그인 상태, 유저 정보 | Zustand | 구조가 단순하고 확장 쉬움 |
페이지 단위 데이터 캐싱 | Zustand or Redux | 비동기 & 캐싱 상태 최적 |
대형 앱, 복잡한 로직 | Redux | 상태 추적 및 DevTools 필요 |
SSR/SEO 기반 앱 (Next.js) | Zustand | 클라이언트 기반으로 최적화 |
🧪 상태 관리 설계 팁
- 전역 상태는 꼭 필요할 때만!
- UI 기능 수준은 Context로 충분
- 복잡한 로직은 Zustand or Redux로 Store 분리
- 상태와 UI는 분리 → Custom Hook 기반 구조 추천
📝 실전 예시: 모달 상태 관리
1. Context로 처리
<ModalContext.Provider value={{ isOpen, setIsOpen }}>
<App />
</ModalContext.Provider>
2. Zustand로 처리
const useModalStore = create((set) => ({
isOpen: false,
open: () => set({ isOpen: true }),
close: () => set({ isOpen: false })
}));
const { isOpen, open, close } = useModalStore();
🔚 마무리 정리
React 상태 관리는 단순히 값 저장이 아니라
"누가", "어디서", "어떻게" 상태를 사용하는지에 따라 구조화하는 것이 핵심입니다.
🔑 핵심 요약
- 상태는 로컬 vs 전역 구분부터 설계
- Context는 간단한 상태
- Zustand는 중소형 앱에서 강력
- Redux는 복잡한 앱, 팀 협업에 적합
- 불필요한 전역 상태는 지양
“지금 설계한 상태 구조, 3개월 뒤에도 명확할까?”
지금 고민한 만큼 유지보수가 편해집니다 😉
반응형