How to persist Mobx data on NextJS

1k Views Asked by At

Problem

After user login user details are saved in mobx state. but after page refresh those data are gone. I want to persist data on mobx state so the user data are stay on mobx state until user logout.

I tried mobx-persist-store but when I go to another page those data are gone again. How can I implement persistence store with or without mobx-persist-store in Next.js?

root-store-provider

import { createContext, FC, useContext } from "react";
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

import { UserStore } from "./user";
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);
  }
}

1

There are 1 best solutions below

0
Leonel Sanches da Silva On

I got to make it work without localforage package. Another thing I noted in your implementation is the use of makePersistable() in RootStore. It should be in your UserStore, like in my example below:

import { makeObservable, observable, action } from "mobx"
import { makePersistable } from 'mobx-persist-store';

export class UserStore {

    id: string = ""
    email: string = ""
    firstName: string = ""
    lastName: string = ""
    phone: string = ""
    loggedIn: boolean = false
    registrationComplete: boolean = false

    constructor(initialData: any = {}) {
        makeObservable(this, {
            id: observable,
            email: observable,
            firstName: observable,
            lastName: observable,
            phone: observable,
            loggedIn: observable,
            registrationComplete: observable,
            setEmail: action,
            setFirstName: action,
            setLastName: action,
            setPhone: action
        })

        makePersistable(this, { 
            name: 'UserStore',
            storage: typeof window !== "undefined" ? window.localStorage : undefined,
            properties: [
                'id', 
                'email', 
                'firstName', 
                'lastName', 
                'phone',
                'loggedIn',
                'registrationComplete'
            ]
        })
        
        this.id = initialData.id
        this.email = initialData.email
        this.firstName = initialData.firstName
        this.lastName = initialData.lastName
        this.loggedIn = initialData.loggedIn
        this.registrationComplete = initialData.registrationComplete
    }

    setId(id: string) {
        this.id = id
    }

    setEmail(email: string) {
        this.email = email
    }

    setFirstName(firstName: string) {
        this.firstName = firstName
    }

    setLastName(lastName: string) {
        this.lastName = lastName
    }

    setPhone(phone: string) {
        this.phone = phone
    }

    setLoggedIn(loggedIn: boolean) {
        this.loggedIn = loggedIn
    }

    setRegistrationComplete(registrationComplete: boolean) {
        this.registrationComplete = registrationComplete
    }

    logout() {
        this.id = ""
        this.email = ""
        this.firstName = ""
        this.lastName = ""
        this.phone = ""
        this.loggedIn = false
        this.registrationComplete = false
    }

    __data() {
        return {
            id: this.id,
            email: this.email,
            firstName: this.firstName,
            lastName: this.lastName,
            phone: this.phone,
            loggedIn: this.loggedIn,
            registrationComplete: this.registrationComplete
        }
    }
}