I can't seem to find a way to set initial checkbox state from MobX store after a fast refresh from Next.js. As soon as i refresh the page, it renders with the state i set before.
For example: i check the checkbox (which has the checked/onChange routed to MobX) -> Page refresh -> The input persists to be checked, while the state is set to false.
I've tried all the other ways to pass the observer HOC (Observer, useObserver), disabling hydration, reworking store, but to no avail.
Here's the code:
store/ThemeStore.ts
import { makeAutoObservable } from 'mobx';
export type ThemeHydration = {
darkTheme: boolean;
};
class ThemeStore {
darkTheme = false;
constructor() {
makeAutoObservable(this);
}
setDarkTheme(value: boolean) {
this.darkTheme = value;
}
hydrate(data?: ThemeHydration) {
if (data) {
this.darkTheme = data.darkTheme;
}
}
}
export default ThemeStore;
pages/index.tsx
import React, { useEffect } from "react";
import { reaction } from "mobx";
import styles from "@/styles/homepage.module.scss";
import { observer } from "mobx-react";
import { useStore } from "@/stores";
const HomePage = observer(function () {
const { themeStore } = useStore();
useEffect(() => {
const re = reaction(
() => themeStore.darkTheme,
(value) => {
const body = document.body;
if (value) {
body.classList.remove("theme-light");
body.classList.add("theme-dark");
} else {
body.classList.remove("theme-dark");
body.classList.add("theme-light");
}
},
{ fireImmediately: true }
);
return () => {
re();
};
}, []);
return (
<div className={styles.container}>
<main className={styles.main}>
<input
type="checkbox"
defaultChecked={themeStore.darkTheme}
onChange={(e) => {
themeStore.setDarkTheme(e.target.checked);
}}
/>
</main>
</div>
);
});
export default HomePage;
stores/index.tsx
import React, { ReactNode, createContext, useContext } from "react";
import { enableStaticRendering } from "mobx-react";
import RootStore, { RootStoreHydration } from "./RootStore";
enableStaticRendering(typeof window === "undefined");
export let rootStore = new RootStore();
export const StoreContext = createContext<RootStore | undefined>(undefined);
export const useStore = () => {
const context = useContext(StoreContext);
if (context === undefined) {
throw new Error("useRootStore must be used within RootStoreProvider");
}
return context;
};
function initializeStore(initialData?: RootStoreHydration): RootStore {
const _store = rootStore ?? new RootStore();
if (initialData) {
_store.hydrate(initialData);
}
// For SSG and SSR always create a new store
if (typeof window === "undefined") return _store;
// Create the store once in the client
if (!rootStore) rootStore = _store;
return _store;
}
export function RootStoreProvider({
children,
hydrationData,
}: {
children: ReactNode;
hydrationData?: RootStoreHydration;
}) {
const store = initializeStore(hydrationData);
return (
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
);
}
Thanks in advance!