Next.js 환경에서 전역상태라이브러리 zustand를 사용하고 있었다.
전역 상태를 사용해야 하면서, 새로 고침 후에도 값이 남아 있도록 스토리지에 값을 저장해야했다.
localstorage hook을 만들어서 사용할 수도 있지만,
이왕 zustand
를 쓰니, 이를 이용해서 스토리지에 저장하기로 하였다.
zustand
의 공식 문서를 확인해보면,
Persist middleware을 이용해 state를 storage에 저장할 수 있다.
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
}
)
)
const StorageKey = 'storage-key';
interface State {
state: boolean;
setState: (state: boolean) => void;
}
공식문서에 나와있는 예시는, javascript 문법으로 typescript의 타입은 알려주지 않았다.
기존에 zustand를 사용하는 방법에서는 (persist middleware 사용 x)
create
옆에 타입을 추가해서 시도해 보았더니 에러만 발생하였다..
에러메시지
'StateCreator<State, [], [["zustand/persist", State]]>' 형식의 인수는 'StateCreator<State, [], []>' 형식의 매개 변수에 할당될 수 없습니다.
'StateCreator<State, [], [["zustand/persist", State]]>' 형식은 '{ $$storeMutators?: [] | undefined; }' 형식에 할당할 수 없습니다.
'$$storeMutators' 속성의 형식이 호환되지 않습니다.
'[["zustand/persist", State]] | undefined' 형식은 '[] | undefined' 형식에 할당할 수 없습니다.
시도해 본 코드
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const useStateStore = create<State>(
persist(
(set) => ({
...
}),
{
name: StorageKey,
},
),
);
persist
의 옆에 persist<State>
과 같이 타입을 추가하니, 의도한대로 타입을 지정하는데 성공하였다!
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const useStateStore = create(
persist<State>(
(set) => ({
state: false,
setState: (state: boolean) => {
set({ state });
},
}),
{
name: StorageKey,
},
),
);
이 글을 처음 쓸 당시에는 persist 옆에 타입을 추가했어야했는데, 최근에 다시 시도해보니 create 옆에 타입을 추가하는 방식으로 바뀐것을 확인했습니다.
따라서 밑과 같이 사용하면 됩니다!
interface State {
bears: number;
addABear: () => void;
}
export const useBearStore = create<State>(
persist(
(set, get) => ({
bears: 0,
addABear: () => set({ bears: get().bears + 1 }),
}),
{
name: StorageKey
}
)
);
기존에 사용하던 방식대로 state와 action을 분리한 훅을 생성해서, store을 사용하였다.
코드
export const useBooleanState = () =>
useRecommendCategoryStore((state) => state.state);
export const useBooleanStateAction = () =>
useRecommendCategoryStore((state) => state.setState);
state와 action을 분리한 훅을 사용하면
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const StorageKey = 'storage-key';
interface State {
state: boolean;
setState: (state: boolean) => void;
}
const useStateStore = create(
persist<State>(
(set) => ({
state: false,
setState: (state: boolean) => {
set({ state });
},
}),
{
name: StorageKey,
},
),
);
export const useBooleanState = () =>
useRecommendCategoryStore((state) => state.state);
export const useBooleanStateAction = () =>
useRecommendCategoryStore((state) => state.setState);
zustand persist를 이용해 storage에 값을 저장한다면,
기본적으로 local storage에 값이 저장되게 된다.
만약 session storage에 저장을 원한다면, storage를 임의로 지정해주어야한다.
const useStateStore = create(
persist<State>(
(set) => ({
state: false,
setState: (state: boolean) => {
set({ state });
},
}),
{
name: StorageKey,
storage: createJSONStorage(() => sessionStorage), // (optional) by default, 'localStorage' is used
},
),
);