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