Zustand+persistでcustom classを保存する

たとえば、以下のようなclassがあるとします。

class Human {
  name: string;
  constructor(name:string){
    this.name = name;
  }

  Hello(){
    console.log(`Hello!! I'm${this.name}!!`)
  }
}

このclassを Zustand の persistミドルウェアを使って、localstorageに保存したいとします。

 

なので以下のようなstoreを作ったとします。

export type HumanStore = {
  human: Human;
  updateHumanName: (newHumanName: string) => void;
};

export const useHumanStore = create()(
  persist(
    (set) => ({
      human: new Human("Alex"),
      updateHumanName: (newHumanName: string) => set({ human: new Human(newHumanName) }),
    }),
    {
      name: "useHumanStore",
      skipHydration: true,
    },
  ),
);

この状態で、たとえばupdateHumanNameを呼んでストアの状態を変更すると、自動でlocalstorageにこのストアがまるごと保存されます。

しかし、保存される際にJSON.stringfyでシリアライズされるので、ただの文字列としてlocalstorageに保存されてしまいます。

なので、デシリアライズ後は、human.Hello()が使えなくなってしまいます。

 

こういうときは、persistの第二引数のオブジェクトにmergeプロパティを追加して、以下みたいに「デシリアライズする際にnew Humanする」な感じで書くと、うまくデシリアライズされます。

export const useHumanStore = create()(
  persist(
    (set) => ({
     ....
    {
     ....
      merge: (persistedState, currentState) => {
        const prev = persistedState as HumanStore;
        return {
          ...currentState,
          human: new Human(prev.human.name),
        };
      },
    },
  ),
);

 

そもそもステートの中にclassを入れるのってどうなの?という気がしますが、個人的にはこの書き方で分かりやすいと思うので、個人開発ではこの書き方を続けたいと思ってます。

それにしてもZustand便利すぎて素晴らしい!!

 

おわり

コメント

タイトルとURLをコピーしました