たとえば、以下のような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便利すぎて素晴らしい!!
おわり
コメント