우당탕탕
Zustand vs Redux 직접 써보고 고른 상태관리 선택 기준 본문
프론트엔드 개발하면서 상태관리 라이브러리를 고르는 일이 생각보다 까다롭다는 걸 절실히 느꼈어요. 저도 처음엔 Redux만 알았는데, 최근에 Zustand까지 직접 써보면서 둘 중 어느 걸 택할지 한참 고민했거든요. 이 글에서는 제가 직접 구현하며 경험한 두 라이브러리의 장단점과, 다른 사람들의 사례도 비교하면서 왜 최종적으로 선택했는지 자세히 풀어볼게요.
Redux로 프로젝트 세팅부터 미들웨어 설정까지 한 경험과 Zustand의 심플한 사용법을 모두 겪어본 관점에서, 성능, 사용 편의성, 확장성, 그리고 유지보수 측면까지 다뤄봤어요. 이 글을 다 읽으면 Zustand와 Redux 중 어떤 상태관리 라이브러리가 내 프로젝트에 맞을지 스스로 판단할 수 있을 거예요.
개발 환경 / 버전 정보
제가 테스트한 환경은 React 18.2 기반이고, Redux는 @reduxjs/toolkit 1.9.5와 react-redux 8.0.5를 썼고, Zustand는 zustand 4.3.9 버전이에요.
두 라이브러리 모두 타입스크립트 지원이 잘 되어 있어서 타입 안전성도 비교했는데, 이 부분도 아래에서 언급할게요.
Zustand vs Redux 직접 써보고 고른 상태관리 관련 정보
Redux는 이렇게 썼어요
처음 Redux를 썼을 때는 액션, 리듀서, 스토어 설정 등 기본 개념부터 완전 생소했어요. 그런데 저는 @reduxjs/toolkit을 적용하면서 번거로운 보일러플레이트가 훨씬 줄어들었더라고요.
// Redux Toolkit 예시: 간단한 카운터 slice
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment(state) {
state.value += 1;
},
decrement(state) {
state.value -= 1;
},
},
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
이렇게 한 파일에 액션과 리듀서가 정리되니까 유지보수가 조금 편해졌지만, 그래도 스토어 설정이나 미들웨어 추가할 때는 약간 복잡할 수밖에 없었어요. 그리고 useSelector 쓸 때마다 selector 최적화도 따로 신경 써야 해서 초반에는 꽤 삽질했죠.
Zustand는 이렇게 썼어요
Zustand는 이름부터 낯설었지만, 직접 써보니까 진짜 심플해서 놀랐어요. 기본적으로 상태를 set과 get 함수로 관리하는 패턴인데, 액션 타입이나 리듀서 함수 같은 개념이 없으니 코드가 확 줄더라고요.
// Zustand 예시: 간단한 카운터 스토어 생성
import create from 'zustand';
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
export default useCounterStore;
컴포넌트에서 호출도 간단해서 const count = useCounterStore(state => state.count); 이런 식으로 쓰면 돼요. Redux처럼 액션 타입, 리듀서 선언이 없으니 훨씬 직관적이고, 추가로 미들웨어 설정 같은 것도 별로 없어서 금방 적응됐죠.
Zustand vs Redux 직접 써보고 고른 상태관리 관련 정보
실제 사용하며 느낀 차이점 정리
- 학습 곡선: Redux는 상태관리 기초 개념(액션, 리듀서 등)을 이해해야 해서 초보가 처음 접하기엔 어려웠어요. Zustand는 API 자체가 단순해서 빠르게 익힐 수 있었습니다.
- 코드 양: Redux는 코드가 상대적으로 장황한 편이에요. 상태와 액션, 리듀서를 각각 만들고 조합하는 과정이 필요하니까요. Zustand는 상태와 상태 변경 함수가 한 자리에서 선언되니 훨씬 간결합니다.
- 성능: 둘 다 상태 변경 시 필요한 컴포넌트만 재렌더링하는 구조지만, Zustand는 selector를 쓰지 않아도 기본적으로 상태의 일부 변경만 구독하는 게 가능해서 렌더링 최적화가 더 자연스러웠어요.
- 디버깅/개발자 도구: Redux는 강력한 devtools가 있어서 액션 흐름과 상태 변화를 시각적으로 파악할 수 있어 편했습니다. 반면 Zustand는 devtools 지원이 있지만, Redux만큼 체계적이지 않았어요.
- 확장성: 대규모 프로젝트에서 Redux는 여러 미들웨어 지원과 엄격한 패턴 덕분에 협업과 유지보수에 유리합니다. Zustand는 심플하지만, 복잡한 비동기 로직이나 대규모 상태 관리에선 한계가 있을 수 있다는 느낌을 받았어요.
여기서 많이 틀립니다: 다른 개발자 사례 비교
제가 직접 써본 결과와 다르게, 인터넷 커뮤니티나 오픈소스에서 본 사례들을 모아보니 다음과 같은 차이가 있었는데요.
- Redux 선호자들: 엄격한 상태관리 규칙과 디버깅 편의성 때문에 대형 엔터프라이즈 프로젝트나 복잡한 앱에 많이 쓰였고, 테스트 코드 작성이 쉽다는 의견이 많았어요.
- Zustand 추천자들: 상태가 단순하거나 중소규모 프로젝트, 빠르게 프로토타입을 만들 때 개발 생산성이 뛰어나다고 평가되더라고요. 특히 React 18의 자동 배치와도 자연스럽게 잘 맞는다는 피드백이 많았어요.
- 혼용 사례: 일부 프로젝트는 Redux를 메인 상태관리로 쓰되, Zustand를 별도 로컬 상태나 특정 컴포넌트 전용 상태로 혼용해서 쓴 팀도 있었습니다. 이렇게 하면 큰 틀은 Redux로 유지하면서도 간단한 상태는 편리하게 관리 가능하대요.
Zustand vs Redux 직접 써보고 고른 상태관리 관련 정보
심화: 타입스크립트와 비동기 처리 차이는?
타입스크립트 적용 시 Redux Toolkit은 액션과 상태 타입을 명확히 분리 가능해서 타입 안전성이 굉장히 좋아요. 반면 Zustand도 타입스크립트 지원이 있지만, 상태 객체와 상태 변경 함수를 직접 작성하는 구조라서 타입 추론이 가끔 까다로울 때가 있어요. 저는 Zustand에서 제네릭으로 명시할 때 조금 수고스럽더라고요.
비동기 처리는 Redux는 보통 redux-thunk나 redux-saga 같은 미들웨어를 써서 관리하는데, 설정이 복잡해서 처음엔 진입 장벽이 있었습니다. Zustand는 비동기 함수 내에서 직접 상태를 set할 수 있어서 구현 자체는 편했는데, 복잡한 비동기 흐름에서는 Redux 쪽이 더 구조화돼 있다는 느낌이었어요.
자주 물어보시는 것들
Q. Redux 쓰다가 Zustand 바로 바꿔도 되나요?
A. 상태관리 규모와 복잡도에 따라 다릅니다. 작은 프로젝트나 프로토타입이면 바로 바꿔도 큰 무리는 없지만, 이미 Redux에 익숙하고 미들웨어나 개발자 도구에 의존하는 프로젝트라면 신중한 검토가 필요해요.
Q. 상태가 너무 많으면 Zustand 성능 저하 없나요?
A. Zustand는 상태 변경 시 구독 중인 상태 부분만 재렌더링해서 성능 최적화가 잘 되어 있지만, 앱 상태가 엄청나게 복잡해지면 복잡한 로직 관리가 어려울 수 있어요. 이럴 때는 Redux가 더 안정적일 수 있죠.
Q. React Query 같은 비동기 상태관리도 같이 써야 할까요?
A. 네, 상태관리 라이브러리들은 보통 UI 상태나 전역 상태를 다루는 데 초점이 맞춰져 있으므로 서버 상태나 비동기 데이터는 React Query 같은 특화 라이브러리를 함께 쓰는 게 좋습니다.
결론적으로, 제 경험담과 여러 사례를 종합해 보면 Zustand는 '간단함과 생산성'이 강점이고, Redux는 '견고한 구조와 확장성'에 무게가 실린 상태관리 라이브러리라고 할 수 있어요. 어떤 프로젝트냐에 따라 충분히 선택지가 달라질 수 있으니, 제 코드 예시와 비교 내용을 참고해 꼭 직접 써보면서 결정하시면 좋겠습니다.
'언어 > JavaScript' 카테고리의 다른 글
| React useEffect 의존성 배열 때문에 헤매다 깨달은 점들 (0) | 2026.08.31 |
|---|---|
| Next.js 13 App Router로 마이그레이션하며 알게 된 비용 차이와 경험 (0) | 2026.08.29 |
| Tailwind CSS 적용하면서 알게 된 초보자용 실전 팁들 (0) | 2026.08.20 |
| React useMemo와 useCallback, 진짜 필요한 순간만 잘 쓰는 방법 (0) | 2026.08.18 |
| JavaScript 클로저 실전에서 헷갈렸던 사례와 직접 겪은 실패담 (0) | 2026.08.15 |
