리액트에서 상태관리를 하는 다양한 방법을 배웠다. useState, useReducer 등 리액트 훅을 활용하는 방법부터 Context API를 사용하는 방법을 배웠다. 각자 직접 코드를 작성해보면서 장단점을 비교해보기도 했는데, Context API를 배웠을 때 props를 넘겨넘겨넘겨 주지 않아도 직접 요청할 수 있다는 점에서 굉장히 편하다고 느꼈다.
26일에는 상태관리 라이브러리 중 하나인 zustand를 배웠다. 느낀점은 그냥 "찢었ㄷㅏ"였다. 정말 상태관리 방법론을 다 찢어버렸다. 엄청 편하고 혁신적이고 쉽다. 이걸 왜 이제야 배웠지 싶고 모든 프론트엔드 개발자는 zustand를 써줬으면 좋겠다.
원티드 프론트엔드 프리온보딩 때 배웠는데 zustand는 독일식 발음으로 "슈스탄트"가 더 옳은 발음법이라고 한다. 뜻도 독일어로 "상태"
(홈페이지 곰돌이가 인상적이어서 zustand = 곰돌이 일줄 알았는데)
이전에 상태관리를 하는 여러 방법을 배웠다. useState부터 시작해서, Context API를 사용하는 방법까지 다양한 방법을 다뤄보았다. 이미 상태관리를 하는 방법이 이렇게 많은데 왜 라이브러리를 쓰는걸까
데이터를 필요로 하는 컴포넌트가 하위 계층에 있거나, 여러 컴포넌트에서 동일한 데이터를 필요로 하는 경우에는 중간 컴포넌트를 통해 props를 전달해야하는 props drilling
이 발생한다.
Context API를 사용하면, props drilling
없이 데이터를 필요로 하는 컴포넌트에서만 불러서 사용할 수 있다.
Context API는 자주 업데이트 할 필요가 없는 데이터에서 주로 사용한다.
Context API에서 상태 값을 변경하면, Provider로 감싼 모든 자식 컴포넌트들이 리렌더링 된다. 이는 불필요한 리렌더링을 유발하고, 어플리케이션의 성능에 영향을 줄 수 있다.
따라서 Context는 전역적으로 사용되는 값이나, 자주 변경되지 않는 값들을 관리하는데 적합하다. Context는 다음 기능들을 구현하는데 자주 사용된다.
1. 테마 설정
2. 사용자 인증 정보
3. 다국어 지원
Context로도 쉽게 상태를 공유할 수 있지만, 리렌더링과 성능 등의 문제로 상태관리 라이브러리를 필요로 한다.
상태관리 라이브러리는 상태 변경에 따른 리렌더링을 효율적으로 관리하고, 복잡한 상태 관리를 단순화 할 수 있다.
상태관리 라이브러리는 그 종류가 매우 다양하다. 유명한걸로는 Redux, React-query,Mobx, Recoil, Jotai, Valtio, Zustand...엄청 많다.
npm trends
사이트에 접속해서 상태관리 라이브러리의 점유율을 확인해보았다.
보라색 그래프가 zustand
의 그래프이다. 노랑색 그래프는 Redux
로, 가장 오래된 라이브러리이니만큼 그 점유율이 1위를 달리고 있다.
현재 두 번째로 점유율이 높은 라이브러리는 zustand
인데, 단순 순위 뿐만 아니라 그 성장세에도 집중해야 한다.
zustand
는 상태적으로 늦게 개발된 라이브러리임에도 불구하고, 2024년 하반기 현재에 들어서서는 상태관리 라이브러리 중 점유율 2위를 차지할 만큼 빠른 성장세를 보이고 있다.(3위와의 격차도 상당히 큰 편)
상태관리 라이브러리가 다양하고, 각각 장단점과 특기가 다른만큼 알아 둘 필요가 있지만, 현재로 봐선 zustand
를 선택하는 것이 좋을 것으로 보인다. 이런 성장세라면 언젠간 Redux
, 밟을 수 있을지도?
곰돌이는 먹이 사슬의 최상위 포식자다. Zustand가 곰돌이 이미지를 쓴데에는, 분명 이런 의미가 있을것이다.
Zustand는 Jared Palmer와 Jotai의 개발자인 Daishi Kato가 개발한 상태 관리 라이브러리이다. Flux 원칙을 바탕으로, 미니멀리즘과 단순성을 강조하는 라이브러리이다.
작은 패키지 크기와 직관적이고 쉬우면서도 강력한 기능 덕분에 많은 사랑을 받고 있다.
- Zustand는 간단한 API로 빠르게 상태 관리를 구현 가능
- React 훅과 유사한 방식으로 상태를 관리
- 내부적으로 Immer를 사용하여 불변성을 쉽게 유지
- 약 1KB로, 매우 가벼운 라이브러리
코드가 정말 간단하다. 최소한의 보일러플레이트로 상태 관리를 구현할 수 있다.
간단한 코드와 훅과 유사한 API 설계로, 리액트 사용경험이 있다면 러닝커브가 매우 낮다.
사용하기 간편하다. Provider로 감싸주지 않아도 된다. 그럼에도 불필요한 리렌더링을 최소화 하여 성능을 최적화 할 수 있다. Context와 달리 변화가 일어나는 경우에만 리렌더링이 발생한다.
Redux DevTools 사용이 가능하다! 디버깅이 편하다...?
물론 단점도 있다. 공식 문서의 설명이 미흡하다. 또한 상대적으로 짧은 역사와 커뮤니티로, 미들웨어 생태계를 가지고 있다.
많은 장점과 쉬운 사용법으로 인해 많은 인기를 얻고 있지만, 그래도 대규모 어플리케이션은 Redux를 사용하는 것이 더 적합하다.
Zustand는 작은 규모의 어플리케이션에 적합하다는 의견이 많고...이미 많은 기업들은 Redux를 사용했기 때문에 레거시 관리의 관점에서도 Redux와 Zustand 둘 다 공부하자😥
먼저 라이브러리를 설치해 주어야 한다.
npm install zustand
위 페이지에 접속하면 메인에 코드 블럭이 하나 있다. store
컴포넌트 만들고 이 코드를 복사해서 붙여넣으면 끝이다.
import { create } from 'zustand'
type Store = {
count: number
inc: () => void
}
const useStore = create<Store>()((set) => ({
count: 1,
inc: () => set((state) => ({ count: state.count + 1 })),
}))
function Counter() {
const { count, inc } = useStore()
return (
<div>
<span>{count}</span>
<button onClick={inc}>one up</button>
</div>
)
}
진짜 끝이다. 타입 정의해주느라 좀 복잡한게 이정도...
create
함수를 import 하는 것만으로도 Zustand의 스토어를 생성하고 사용할 수 있다. 별도의 Provider
가 없다.
create
함수는 상태와 액션을 정의하는 콜백을 받으며, 이 콜백 함수는 set
함수를 매개변수로 받고, 상태와 액션을 포함하는 객체를 반환한다. 이 객체가 스토어의 초기 상태이다.
스토어는 상태 변수(bears)와, 해당 상태를 업데이트 하는 액션(increasePopulation, removeAllBears)로 구성된다.
set
함수를 사용하여 상태를 업데이트 한다. 새로운 상태 객체나 현재 상태를 받아 새 상태를 반환하는 함수를 인자로 받는다.
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>
}
create
함수는 useStore
훅을 반환하는데, 이 훅을 사용하여 컴포넌트에서 스토어의 상태나 액션에 접근할 수 있다. 선택함수를 인자로 전달하여 컴포넌트에서 필요한 상태나 액션만을 선택적으로 가져와 사용할 수 있다.
강력한 상태관리 라이브러리인 Zustand를 알아보았다.
무조건 라이브러리를 쓰자!는 아니다...useReducer와 Context로도 충분한데 Redux 같은 복잡한 상태관리 라이브러리를 도입하는 것은 오히려 오버엔지니어링이 될 수 있다. 어떤 프로그램이든 프로그램의 요구사항, 목적을 충분히 이해하고 적합한 기술을 도입하는 것이 좋다.
그치만 Redux면 몰라도 zustand는 너무 가볍고 사용하기 편해서 굳이 Context...?라는 생각이 들기도 하고...리덕스처럼 코드가 많아지는 것도 아니고 나는 전부 다 zustand로 만들고 싶어.