Zustand란?
Zustand는 상태관리 라이브러리다. 상태는 React의 state할때 그 상태이다. 그리고 Zustand는 독일어로 상태라는 뜻임. (나도 라이브러리를 만들면 이름을 Sangte라고 지을 수 있을까?)
리액트도 useState, useContext가 있는데 왜 라이브러리를 쓸까?
- prop drilling - 모든 상태를 prop으로 주고받기는 힘들다.
- 한 context를 같이 쓰는 모든 컴포넌트가 다같이 렌더되어 쓸데없는 렌더가 일어난다.
Zustand의 장점
- state 정의랑 그걸 변경하는 함수를 한곳에 쓸 수 있다.
- 그리고 글로벌하게 어디서나 갖다쓸 수 있다. 밑에 코드 써놨지만 만든 함수를 import해서 쓸 수 있다. (다른 상태관리라이브러리는 안써봐서 모르겠지만 꽤나 간편한 것 같다)
- 정확히 변한 값을 쓰는 컴포넌트만 re-render한다.
- Redux는 context provider로 컴포넌트를 wrap해야 한다는데 그런 거 없다.
use when… | Recommended |
---|---|
State is local to a component | useState |
Sharing state between a few components | useContext |
Global state, lots of components need it | Zustand / Redux |
Need performance + simplicity | Zustand |
쓰는법
npm install zustand
- create a store
import { create } from 'zustand' const useStore = create((set) => ({ bears: 0, increasePopulation: () => set((state) => ({ bears: state.bears + 1 })), removeAllBears: () => set({ bears: 0 }), updateBears: (newBears) => set({ bears: newBears }), }))
- bind the component
function BearCounter() { const bears = useStore((state) => state.bears) return <h1>{bears} bears around here...</h1> } function Controls() { const increasePopulation = useStore((state) => state.increasePopulation) return <button onClick={increasePopulation}>one up</button> }
예전에 내가 어떻게썼는지 복습
실시간으로 호버한 물체에 따라 뭔가 스타일을 바꿔야 할 때 사용했다. 날짜를 가지고 있는 calendar-entry에 호버하면 → calendar-head에 해당 날짜를 보여준다.
-
lib/useHoveredStore.ts
import { create } from 'zustand'; interface HoveredEntryState { hoveredDate: {startDate: string, endDate: string} | null; setHoveredDate: (date: {startDate: string, endDate: string} | null) => void; } export const useHoveredStore = create<HoveredEntryState>((set) => ({ hoveredDate: null, setHoveredDate: (date) => set({ hoveredDate: date }), }));
state랑 setState를 같이 만들고
-
ui/…/calendar-entry.tsx
import { useHoveredStore } from "@/app/lib/useHoveredStore"; ... const setHoveredDate = useHoveredStore((state) => state.setHoveredDate); ... < ... onMouseEnter={() => setHoveredDate({ startDate: data.startDate, endDate: data.endDate })} onMouseLeave={() => setHoveredDate(null)} >
호버하면 hoveredDate를 set하고, 딴데가면 초기화
-
ui/…/calendar-head.tsx
import { useHoveredStore } from "@/app/lib/useHoveredStore"; ... const hoveredDate = useHoveredStore((state) => state.hoveredDate); ... {hoveredDate ? ( <div className="relative bg-gray-200 mix-blend-multiply w-auto rounded-full h-8" style={{ gridRow: `1 / span ${entry_count}`, gridColumnStart: (+new Date(hoveredDate.startDate) - +new Date(calendarEntries[0].startDate)) / (1000 * 60 * 60 * 24)+1, gridColumnEnd: (+new Date(hoveredDate.endDate) - +new Date(calendarEntries[0].startDate)) / (1000 * 60 * 60 * 24)+2 }} > </div> ) : ( null )}
hoveredDate가 있으면(현재 호버 중이면) 색깔 막대기를 그 날짜에 맞는 위치에다 만들어주고, 없으면 null