🧎

zustandでLocal Storageから取得した値を待つ

2024/11/29に公開

はじめに

Next.jsで状態管理に zustand を使い、Local Storageから取得した値を判定して処理の分岐をしたときの記録です。
サンプルコードは、ファイル内の全コードではなく注目箇所だけ書いていますのでご注意ください。

分岐処理の概要

画面で以下のような分岐処理を実装していました。

pages.tsx
// Local Storageに保存したidの値を取得
const id = useStore(useIdStore, (state) => state.id);

// id === undefinedなら別ページに遷移
useEffect(() => {
  if (id === undefined) router.push('/another-page')
}, [id])

問題点

id の初期値は undefined にしていて、id を取得した時の値は以下の3パターンになります。

(a) Local Storageから id を取得中・・・ id = undefined
(b) idが登録されていない・・・ id = undefined
(c) idが登録されている・・・ id = 'xxxxxxxxxxxxxxxx'

(a)の変数取得中の時間があり、id が存在していても id === undefined の条件が発動してしまうのが問題でした。

解決法1

storeでgetterを使って、その関数に対して判定処理をすることで、戻り値を待ってから判定されるようにしました。

IdStore.ts
export const useIdStore = create<State & Action>()(
  persist(
    (get) => ({
      getId: () => {
        get().id;
      },
    }),
    {
      name: "id-storage",
    }
  )
);

解決法2

Local Storageに id が保存されていない場合は id = '' を最初にセットするための初期化関数を作り、undefined '' 'xxxxxxxxxxxxxxxx' の3つの状態を作るようにしました。
この場合は、getterではなく直接変数の値を取得しています。

IdStore.ts
export const useIdStore = create<State & Action>()(
  persist(
    (set, get) => ({
      id: undefined,
      initId: () => {
        if (get().id === undefined) set(() => ({ id: "" }));
      },
    }),
    {
      name: "id-storage",
    }
  )
);
pages.tsx
// Local Storageに保存したidの値を取得
const id = useStore(useIdStore, (state) => state.id);
const initId = useStore(useIdStore, (state) => state.initId);

// Local Storageにidが存在しなかったら初期化
useEffect(() => {
  initId()
}, [initId])

// id === ''なら別ページに遷移
useEffect(() => {
  if (id === '') router.push('/another-page')
}, [id])

おわりに

記事用にコードをコンパクトに新しく書いているため、間違いなどあればお知らせください。

Discussion