store.ts 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { create } from "zustand";
  2. import { combine, persist, createJSONStorage } from "zustand/middleware";
  3. import { Updater } from "../typing";
  4. import { deepClone } from "./clone";
  5. import { indexDBStorage } from "@/app/utils/indexDB-storage";
  6. type SecondParam<T> = T extends (
  7. _f: infer _F,
  8. _s: infer S,
  9. ...args: infer _U
  10. ) => any
  11. ? S
  12. : never;
  13. type MakeUpdater<T> = {
  14. lastUpdateTime: number;
  15. markUpdate: () => void;
  16. update: Updater<T>;
  17. };
  18. type SetStoreState<T> = (
  19. partial: T | Partial<T> | ((state: T) => T | Partial<T>),
  20. replace?: boolean | undefined,
  21. ) => void;
  22. export function createPersistStore<T extends object, M>(
  23. state: T,
  24. methods: (
  25. set: SetStoreState<T & MakeUpdater<T>>,
  26. get: () => T & MakeUpdater<T>,
  27. ) => M,
  28. persistOptions: SecondParam<typeof persist<T & M & MakeUpdater<T>>>,
  29. ) {
  30. persistOptions.storage = createJSONStorage(() => indexDBStorage);
  31. return create(
  32. persist(
  33. combine(
  34. {
  35. ...state,
  36. lastUpdateTime: 0,
  37. },
  38. (set, get) => {
  39. return {
  40. ...methods(set, get as any),
  41. markUpdate() {
  42. set({ lastUpdateTime: Date.now() } as Partial<
  43. T & M & MakeUpdater<T>
  44. >);
  45. },
  46. update(updater) {
  47. const state = deepClone(get());
  48. updater(state);
  49. set({
  50. ...state,
  51. lastUpdateTime: Date.now(),
  52. });
  53. },
  54. } as M & MakeUpdater<T>;
  55. },
  56. ),
  57. persistOptions as any,
  58. ),
  59. );
  60. }