※ 해당 블로그는 아래 참조 링크의 블로그 글을 정리 및 번역한 포스트입니다.
Zustand를 알아보기 전에,리액트에서의 전역 상태 관리란 무엇인지부터 이해해 봅시다. 전역 상태 관리란 앱의 중앙에 위치함으로써 어느 컴포넌트든 이 데이터(상태)에 접근할 수 있으며 상태 변경이 가능합니다.
Zustand는 작은 용량, 빠른 속도 그리고 확장 가능성을 자랑하는 상태 관리 라이브러리입니다. 단순화시킨 Flux 구조와 React hooks를 기반으로 만들어져 특정 boilerplate 코드 없이도 쉽게 사용할 수 있습니다.
1.16kb라는 번들 사이즈를 가진 Zustand는 용량이 작은 상태 관리 라이브러리들 중 하나입니다. 깃허브에선 30.4k라는 스타수를 보유하고 있으며 이는 redux, mobX, jotai보다도 높은 스타수입니다. Zustand의 단순함과 쉬운 사용성 덕분에 개발자들 사이에서 리액트 앱의 상태 관리 라이브러리로서 점차 유명세를 얻고 있죠.
Redux는 유연한 방식으로 어플리케이션의 상태를 관리하기 위한 고급 기능을 제공하는 강력한 라이브러리입니다. 규모가 크고 복잡한 소프트웨어 어플리케이션에서 흔히 사용되며 상태 관리에 보다 강력한 접근이 필요한 경우에 유용합니다. 효과적인 사용을 위해 더 많은 설정과 학습을 수반하지만, Redux는 React 뿐만 아니라 다른 시나리오에서도 사용이 가능합니다.
코드 샘플을 보면 Redux 대신 Redux Toolkit을 사용합니다. 코드를 간결화 해 주기 때문이죠. 스토어는 리듀서를 생성하거나 어플리케이션의 상태를 유지 시켜 주는 슬라이스를 생성함으로써 초기화 됩니다. 스토어를 통해 상태는 업데이트 되고, 이러한 상태 변화는 해당 상태에 의존하는 모든 컴포넌트의 리랜더링을 유발합니다.
import { createSlice } from '@reduxjs/toolkit'
const initialState = {
value: 0,
}
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
// 리덕스 툴킷은 리듀서에서 "뮤테이트" 로직을 생성하게 해 줍니다.
// Immer 라이브러리를 사용하기 때문에 실제로 상태값에 변화를 주는 건 아닙니다.
// Immer는 "임시 상태"의 변경을 감지하고 이러한 변경을 기반으로 하는 새로운 불변의 상태를 생성합니다.
state.value += 1
},
decrement: (state) => {
state.value -= 1
},
incrementByAmount: (state, action) => {
state.value += action.payload
},
},
})
// Action creators are generated for each case reducer function
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
increment와 decrement라는 액션을 사용하기 위해선 useSelector
와 useDispatch
훅을 import 해야합니다. 이러한 방식은 유연성과 속도를 제공하지만, 문법과 API가 복잡해 질 수 있습니다. 개인적으로 간단한 기능 구현을 위해 필요한 모든 보일러플레이트 코드를 생성하는 건 좀 번거로운 거 같아요.
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './counterSlice'
export function Counter() {
const count = useSelector((state) => state.counter.value)
const dispatch = useDispatch()
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>
</div>
</div>
)
}
Zustand 얘기를 해 보자면, 아래의 코드를 보는 것만으로도 Zustand의 미(美)를 알 게 될 겁니다. Zustand로부터 create를 import 하는 것만으로도 Zustand의 스토어와 리듀서를 사용할 수 있어요. create에는 콜백 함수가 주어지는데 여기엔 set 함수가 포함되어 있습니다. set 함수는 스토어 내의 변수를 업데이트 시키기 데에 사용됩니다. 초기의 상태와 그것의 초기값, 그리고 increasePopulation
과 removeAllBears
라는 액션이 들어있습니다. 이 액션들은 set 함수를 호출해 당신이 원하는 대로 값을 업데이트 하죠. 그 이상의 보일러플레이트 코드는 필요 없어요. 아주 간단합니다. useStore
는 컴포넌트 내부에서 사용할 수 있는 훅을 반환하죠.
import { create } from 'zustand'
const useStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))'
useStore
훅을 사용하면 당신의 컴포넌트를 provider로 감쌀 필요가 없고 중첩된 코드를 걱정할 필요도 없이 쉽게 상태과 액션에 접근이 가능합니다. Redux와 비교하면 코드가 훨씬 더 간단하고 읽기도 편하죠. 게다가 컴포넌트가 리렌더링 되는 때를 걱정하지 않아도 돼요. 훅이 다 알아서 처리해 주거든요.
function BearCounter()
const bears = useStore((state) => state.bears)
return <h1>{bears} around here...</h1>
}
function Controls() {
const increasePopulation = useStore((state) => state.increasePopulation)
return <button onClick={increasePopulation}>one up</button>
}{
Redux를 손절하고 Zustand로 갈아탈까하는 질문은 흔합니다. 거두절미하고 대답은 No예요. 두 라이브러리 모두 각자의 장단점이 있고, 선택은 철저히 프로젝트의 요구사항에 의거합니다.
Zustand는 복잡한 상태 관리가 필요 없는 작은 규모의 프로젝트에 적합한 가벼운 상태 관리 라이브러리입니다. 간단하고 직관적인 API를 제공하고 Redux보다 더 간결한 방법으로 상태 관리를 해 주죠.
반면에 Redux는 복잡한 상태 관리를 필요로 하고 긴 개발 기간이 소요되는 큰 규모의 프로젝트에 알맞는 강력한 상태 관리 라이브러리입니다. 더욱 구조적이고 표준화 된 상태 관리 방식을 제공하는데 이는 일관성과 팀 멤버간의 협력을 유지하는 데에 도움을 주죠.
요약하자면, Zustand와 Redux 모두 모던 웹 개발에서 각자의 위치를 가지고 있으며, 선택은 프로젝트의 구체적인 요구사항이나 제약사항에 따라야 한다는 겁니다.
🔍 개인적으로 좋았던 레딧 답글
만일 비교하자는 게 Zustand와 오리지널 Redux에 대한 거라면 꽤 극명한 차이가 있어. 이건 공평한 비교가 아냐. Redux Toolkit(RTK)은 Redux에서 권장하는 구현 방식이야. 얘네는 연관성이 크지. 내가 생각하는 요즘의 가장 큰 결정 중 하나는 data fetching 레이어로 무얼 사용할지야. React-Query(RQ)의 성능은 뛰어나고 주목을 받고 있어. 만약 너가 RQ를 사용할 줄 알고 좋아한다? 나라면 Zustand를 택할 거 같다. RQ와 Zustand는 현재 내가 선호하는 조합이거든. Redux는 RTK Query라는 게 있으니까 RQ가 맘에 들지 않는다면 이 조합으로 가면 되겠지. 이제 React Router도 data fetching 패키지를 갖고 있다고 하던데.
자, 내가 왜 Redux냐 Zustand냐 라는 질문에서 data fetching 얘기를 많이 하고 있느냐? 너가 관리해야 하는 상태에는 두 가지 다른 종류의 상태가 있는데, 앱 상태와 서버 상태라는 거야. RTK나 Zustand는 클라이언트 상태 관리에 좋은 툴인 반면, RTK Query와 RQ는 서버 상태 관리를 위한 거야. 개인적으로 나는 이 두가지를 분리시키는 걸 좋아해.
🔗 참조