외주 프로젝트를 하는 중에 다음과 같은 문제가 발생했다.
사용자의 행동에 따라, ZuStand의 persist를 사용하여 localstorage에 저장된 값이 변화한다. 이 변화한 값을 페이지 이동 시 즉시 화면에 보여줘야 한다. 그러나 persist를 이용한 ZuStand는 예상과는 다르게 동작했다.
애플리케이션이 처음 실행될 때, persist 미들웨어는 지정된 스토리지에서 데이터를 읽어와 Zustand 스토어를 "rehydrate"합니다. 즉, 저장된 상태를 다시 불러와 초기 상태로 설정합니다.
persist를 이용해 만들어진 최초의 상태, 즉 아무 값이 저장되지 않은 상태가 zuStand에 저장된 상태라 localStorage에서 변화한 값이 useState를 쓸 때 처럼, 화면의 리렌더링이 되지 않았던 것! 새로고침을 하면 로컬스토리지를 다시 읽어오기에 최신의 값을 불러올 수 있게 되지만, 새로고침을 하기 전까지는 '이전의 값' 을 계속 갖고 있는 것이 문제였다.
해결은 의외로 간단했다.
https://github.com/pmndrs/zustand/discussions/1614
https://zustand.docs.pmnd.rs/integrations/persisting-store-data#how-can-i-rehydrate-on-storage-event
공식 문서에 아래와 같이 적혀있다.
How can I rehydrate on storage event
You can use the Persist API to create your own implementation, similar to the example below:
type StoreWithPersist = Mutate<StoreApi<State>, [["zustand/persist", unknown]]>
export const withStorageDOMEvents = (store: StoreWithPersist) => {
const storageEventCallback = (e: StorageEvent) => {
if (e.key === store.persist.getOptions().name && e.newValue) {
store.persist.rehydrate()
}
}
window.addEventListener('storage', storageEventCallback)
return () => {
window.removeEventListener('storage', storageEventCallback)
}
}
const useBoundStore = create(persist(...))
withStorageDOMEvents(useBoundStore)
store.persist.rehydrate()를 쓰면, storage 이벤트를 사용하여 변경된 값을 즉시 zuStand에 할당해 불러올 수 있다.
나는 페이지를 로드 할 때 (컴포넌트가 마운트 될 때) 직전에 변경된 로컬 스토리지의 값을 보여주는 기능을 구현해야 했으므로, 다음과 같이 사용했다.
1. 먼저, store를 생성한다.
import { create } from "zustand";
import { createJSONStorage, persist } from "zustand/middleware";
type TelStoreType = {
telId?: string; // 전화기 ID
telno?: string; // 전화번호
setTelInfo: (telId: string, telno: string) => void;
clear: () => void;
};
export const useTelStore = create<TelStoreType>()(
persist(
(set) => ({
setTelInfo: (telId, telno) => set({ telId, telno }),
clear: () =>
set(() => ({
telId: "",
telno: "",
})),
}),
{
name: "selected-tel",
storage: createJSONStorage(() => localStorage),
}
)
);
2. 스토어를 사용하는 곳에서, persist의 rehydrate를 통해 항상 최신의 값을 가져온다.
useEffect(() => {
useTelStore.persist.rehydrate();
}, []);
'프로젝트 > React 프론트 프로젝트' 카테고리의 다른 글
[React] Zustand의 persist (1) | 2024.11.27 |
---|---|
[React] 값이 없는 상태를 어떻게 관리해야 할까? undefined와 null (1) | 2024.11.27 |
[React] Zustand를 이용하여 useModal 훅 만들기 (0) | 2024.11.27 |
[React] 보일러 프로젝트 - 프론트 완성 , + (01.20 회원가입 백엔드까지 완성) (0) | 2023.01.19 |
[React] My Portfolio React 프로젝트 (1) | 2023.01.14 |