- Published on
[React] 상태 관리 라이브러리, Zustand 알아보기
- Authors
- Name
- Gecko Baem
서론
React를 활용하여 애플리케이션을 구축할 때, 컴포넌트는 자체적인 지역 상태를 갖추게 된다.
그러나 프로젝트의 규모가 커지고 복잡해지며 여러 컴포넌트 간에 데이터 공유가 필요한 상황에서는 지역상태에만 의존하게 된다면 Prop Drilling 이 발생하고, 이는 곧 어려운 상태 동기화와 코드의 복잡성이라는 문제를 불러온다.
이를 해결하기 위해서 React에서 제공하는 전역 상태 관리 도구인 Context API 를 사용할 수 있지만 이것에도 한계가 있다.
상태가 변경 된다면 이를 참조하는 컴포넌트들이 리렌더링이 되는데, 이는 규모가 큰 프로젝트 에서는 성능 문제가 발생한다.
이러한 문제로 프로젝트 규모가 클 때는. Redux, Recoil 등 라이브러리를 사용하는 것이 좋다.
전역 상태 관리 라이브러리
React에는 다양한 전역 상태 라이브러리로 Redux, Zustand, Jotai를 많이 사용하는데, 이 중 Redux와 Zustand에 대해서 이야기 할 것이다.
Redux
Redux는 9년 전에 출시하여, 현재 실무 환경에서 가장 많이 사용하는 라이브러리이다.
아래는 이해를 위한 간단 예시이다.
- 액션 생성
// 액션 타입 정의
const INCREASE = 'INCREASE';
// 액션 생성 함수
const increase = () => ({ type: INCREASE });
export { INCREASE, increase };
- 리듀서 생성
import { INCREASE } from './actions';
// 초기 상태
const initialState = { count: 0 };
// 리듀서 함수
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case INCREASE:
return { count: state.count + 1 };
default:
return state;
}
};
export default counterReducer;
- 스토어 생성
import { createStore } from 'redux';
import counterReducer from './reducer';
// 스토어 생성
const store = createStore(counterReducer);
export default store;
- 사용하기
import store from './store';
import { increase } from './actions';
// 초기 상태 출력
console.log(store.getState()); // { count: 0 }
// 액션 발생
store.dispatch(increase());
// 업데이트된 상태 출력
console.log(store.getState()); // { count: 1 }
// 한 번 더 액션 발생
store.dispatch(increase());
// 업데이트된 상태 출력
console.log(store.getState()); // { count: 2 }
설명:
- 액션:
increase()
는 "증가" 액션을 나타내는 객체를 생성한다. - 리듀서:
counterReducer
는 액션에 따라count
를 업데이트한다. - 스토어:
store
는 애플리케이션의 상태를 저장하고 관리한다. - 사용:
store.dispatch()
로 액션을 발생시키고,store.getState()
로 현재 상태를 가져온다.
위 상황에서 Redux는 액션, 리듀서, 스토어 등 특정 패턴을 요구한다. 이러한 점은 반복 코드가 많아질 수 밖에 없는데, 코드가 복잡해지면 유지보수에 부담이 되는 문제가 발생한다.
Zustand
Zustand는 6년 전에 출시한 전역 상태 관리 라이브러리로, 복잡한 설정 없이 쉽고 간단하게 전역 상태를 관리 할 수 있어 개발자에게 인기가 많다.
아래는 이해를 위한 간단 예시이다.
- 스토어 생성
import create from 'zustand';
const useCounterStore = create((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
}));
export default useCounterStore;
- 사용하기
import useCounterStore from './counterStore';
// 스토어 사용
const count = useCounterStore((state) => state.count);
const increase = useCounterStore((state) => state.increase);
// 초기 상태 출력
console.log(count); // 0
// 상태 변경
increase();
// 업데이트된 상태 출력
console.log(useCounterStore.getState().count); // 1
// 한 번 더 상태 변경
increase();
// 업데이트된 상태 출력
console.log(useCounterStore.getState().count); // 2
설명:
- 스토어 생성:
create()
함수로 스토어를 만들고,count
와increase
함수를 정의한다. - 상태 접근:
useCounterStore()
훅을 사용하여 스토어의 상태와 함수에 접근한다. - 상태 변경:
increase()
함수를 호출하여count
를 증가시킨다. - 상태 읽기:
useCounterStore.getState().count
또는 훅을 사용하여 업데이트된 상태를 읽는다.
위 예시를 본다면 Redux처럼 액션과 리듀서를 따로 생성하지 않고, 스토어 내에서 상태와 변경 함수를 관리하는 모습을 볼 수 있다.
결론
이 글의 주제가 Zustand 중점이라 해당 라이브러리의 장점 위주로 서술 한 점을 감안하길 바란다.
Redux는 강력한 Middleware 지원과 예측 가능한 상태 관리 방식, 풍부한 개발자 도구를 제공해 복잡한 상태 관리를 안정적으로 처리한다.
Zustand는 간결한 API와 성능 최적화로 직관적이고 효율적인 상태 관리를 돕는다.
이 글이 ‘어떤 도구가 애플리케이션의 상태 관리에 더 적합한지’ 판단하는 데 도움이 되기를 바란다.
Redux와 Zustand의 특성을 잘 이해하고, 적절한 도구를 선택해 상태 관리 환경을 효율적으로 구축하여 완성도 높은 애플리케이션을 개발하길 바란다.