상태 관리 라이브러리 중 zustand를 종종 사용해 정리하고자 한다.
리액트에서의 전역 상태 관리
전역 상태 관리란 앱의 중앙에 위치함으로써 어느 컴포넌트든 이 데이터(상태)에 접근할 수 있으며 상태 변경이 가능하다. 전역 상태관리를 지원하는 api에는 react에 내장된 useContext 훅을 포함하여 redux, recoil, zustand, zotai, react-query 등 다양한 서드파티 라이브러리들까지 존재한다.
zustand 란 ?
Zustand는 작은 용량( 1.16kb라는 번들 사이즈 ), 빠른 속도 그리고 확장 가능성을 자랑하는 상태 관리 라이브러리이다
단순화시킨 Flux 구조와 React hooks를 기반으로 만들어져 특정 boilerplate 코드 없이도 쉽게 사용할 수 있다.
추가 설명
Flux 구조
boilerplate 코드
"Boilerplate 코드"는 개발할 때 자주 반복적으로 작성해야 하는 기본적인 코드 템플릿을 의미한다. 이 코드는 주로 설정, 초기화, 기본적인 구조 등을 포함하며, 특정 작업을 수행하기 위해 반드시 작성해야 하지만, 대부분의 경우 변경 없이 그대로 사용되는 경우가 많다.
=> 예를 들어, Redux에서는 액션(action), 리듀서(reducer), 스토어(store) 설정 등에서 많은 boilerplate 코드가 필요하다. Zustand와 같은 라이브러리들은 이러한 반복적인 코드 작성 없이 간단하게 상태 관리를 시작할 수 있도록 도와준다
=> Boilerplate 코드의 장점으로는 개발자가 반복적인 작업이나 하드 코딩에 시간을 낭비하지 않고, 중요한 로직이나 기능 구현에 집중할 수 있도록 해준다는 점이 있습니다. 예를 들어, create-react-app을 활용하면 미리 갖춰진 기본 구조를 제공받아, 개발자는 그 위에 필요한 기능을 추가하여 빠르게 개발을 진행할 수 있습니다.
zustand 사용법
설치
npm install zustand //or yarn add zustand
상태 관리
아래 zustand는 토글 상태를 공유하기 위한 코드이다.
//store/helpStore.ts import { create } from "zustand"; interface HelpState { showHelp: boolean; toggleShowHelp: () => void; } export const helpStore = create<HelpState>((set) => ({ showHelp: false, toggleShowHelp: () => set((state) => ({ showHelp: !state.showHelp })), }));
생성된 상태를 필요한 곳에 불러다가 사용하면 된다.
import { helpStore } from "@/store/helpStore"; export default function Test() { const { showHelp, toggleShowHelp } = helpStore(); return ( <> <button onClick={toggleShowHelp} style={{ backgroundColor: "#4072ee" }}> 도움말 </button> {showHelp && ( <div css={selectHelpArea}> <div className="ment"> <p>도움이 필요한 영역을 선택하세요.</p> <div onClick={toggleShowHelp} className="close"> 닫기 </div> </div> </div> )} </> ) }
localstorage에 저장하는 방법
zustand에서는 Persist middleware을 이용해 state를 storage에 저장할 수 있다.
아래 zustand는 블로그에서 포스트 뷰 스타일과 순서를 저장하고 잇다.
import { create } from "zustand"; import { persist } from "zustand/middleware"; interface PageStore { viewStyle: string; sortedContent: string; setViewStyle: (style: string) => void; setSortedContent: (content: string) => void; } const createPageStore = (name: string) => create( persist<PageStore>( (set) => ({ viewStyle: "gallery", sortedContent: "latest", setViewStyle: (style: string) => set({ viewStyle: style }), setSortedContent: (content: string) => set({ sortedContent: content }), }), { name: `${name}_page_state` } ) ); export const useBlogPageStore = createPageStore("blog"); export const useProjectPageStore = createPageStore("project");
생성된 상태를 필요한 곳에 불러다가 사용하면 된다.
import { useBlogPageStore, useProjectPageStore } from "@/store/pageStore"; export default function Test() { const { viewStyle, sortedContent, setViewStyle, setSortedContent } = getStore; return ( <> <div> <p>레이아웃</p> <div onClick={() => setViewStyle("gallery")}> <span>갤러리</span> </div> <div onClick={() => setViewStyle("list")} > <span>리스트</span> </div> </div> <div> <p>정렬</p> <div onClick={() => setSortedContent("latest")}> <span>최신순</span> </div> <div onClick={() => setSortedContent("registration")}> <span>등록일순</span> </div> </div> </> ) }
결과
만약 localStorage외에 다른 storage에 저장하고 싶으면 storage: createJSONStorage(() => sessionStorage) 추가하면 된다.
import { create } from 'zustand' import { persist, createJSONStorage } from 'zustand/middleware' export const useBearStore = create( persist( (set, get) => ({ bears: 0, addABear: () => set({ bears: get().bears + 1 }), }), { name: 'food-storage', // name of the item in the storage (must be unique) storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used } ) )
참고