quarrant / mobx-persist-store

Persist and rehydrate observable properties in mobx store.
268 stars 14 forks source link

Next.js compatible? #98

Closed smamun19 closed 1 year ago

smamun19 commented 1 year ago

Does this package work with next.js? If it does , how do I configure it with next.js?

codeBelt commented 1 year ago

You need to do typeof window !== 'undefined' for storage. See below:

export class UserStore {
  user: IUser | null = null;

  constructor() {
    makeAutoObservable(this, {}, { autoBind: true });

    makePersistable(this, {
      name: "UserStore",
      properties: ["user"],
       storage: typeof window !== 'undefined' ? window.localStorage : undefined,
    });
  }
}
smamun19 commented 1 year ago

Thanks for your answer. I am facing another issue that is when I go another page the data do not persist. It persist only at home page

codeBelt commented 1 year ago

I would have to see your store setup. Can you provide snippets of you code?

smamun19 commented 1 year ago

rootStoreProvider.tsx

import { RootStore } from "./root";

const RootStoreContext = createContext<RootStore>(new RootStore());

export const useStore = () => {
  const context = useContext(RootStoreContext);

  if (context === undefined) {
    throw new Error("useStore must be used within StoreProvider");
  }

  return context;
};

let rootStore: RootStore | undefined;

const initializeStore = (initialData?: RootStore) => {
  const _rootStore = rootStore ?? new RootStore();

  if (initialData) {
    _rootStore.hydrate(initialData);
  }

  if (typeof window === "undefined") return _rootStore;

  if (!rootStore) rootStore = _rootStore;

  return _rootStore;
};

interface Props {
  children: React.ReactNode;
  intialState?: RootStore;
}

export const RootStoreProvider: FC<Props> = ({ children, intialState }) => {
  const store = initializeStore(intialState);
  return (
    <RootStoreContext.Provider value={store}>
      {children}
    </RootStoreContext.Provider>
  );
};

rootStore.ts

import { hydrateStore, makePersistable } from "mobx-persist-store";
import localforage from "localforage";

export class RootStore {
  user: UserStore;

  constructor() {
    this.user = new UserStore(this);

    makePersistable(
      this.user,
      {
        name: "RootStore",
        properties: ["details", "cart"],
        storage: typeof window !== "undefined" ? localforage : undefined,
      },
      { delay: 200, fireImmediately: false }
    );
  }

  async hydrate(data: RootStore): Promise<void> {
    await hydrateStore(data);
  }
}
codeBelt commented 1 year ago

It might be an issue with how you use hydrateStore. Try:

async hydrate(data: RootStore): Promise<void> {
-    await hydrateStore(data);
+    await hydrateStore(this.user);
}

Also every time RootStore is created you should use https://github.com/quarrant/mobx-persist-store#stoppersisting to make sure you clean up.

Take a look at how I did MobX in Next.js https://github.com/codeBelt/react-mobx-persist-store-example .

I would put makePersistable inside UserStore and not within RootStore.

smamun19 commented 1 year ago

Sorry for the late reply. I'll check your repo as soon as I return home. Would you please elaborate the last part? Why should I put makePersistable inside UserStore ?

codeBelt commented 1 year ago

I think the individual stores should be responsible for persisting their own data. What if you added another store to RootStore? How would you persist that data in the RootStore?

export class RootStore {
  user: UserStore;
  anotherUser: AnotherStore;

  constructor() {
    this.user = new UserStore(this);
    this.anotherStore = new AnotherStore(this);
  }
}
export class AnotherStore {
  someData: number = 0;
  otherData: string = '';

  constructor() {
    makeAutoObservable(this, {}, { autoBind: true });

    makePersistable(this, {
      name: "AnotherStore",
      properties: ["someData", "otherData"],
       storage: typeof window !== 'undefined' ? window.localStorage : undefined,
    });
  }
}

https://github.com/codeBelt/react-mobx-persist-store-example/blob/main/src/stores/auth/AuthGlobalStore.ts

codeBelt commented 1 year ago

Also if you have multiple stores with the same storage you look at https://github.com/quarrant/mobx-persist-store#global-configuration. It is one less thing to repeat in your code.

https://github.com/codeBelt/react-mobx-persist-store-example/blob/main/src/stores/GlobalStore.ts#L19-L27

smamun19 commented 1 year ago

Thank you very much for your valuable time :) I have successfully configured mobx . I am closing this issue now.