I always have to restart the dev server for displaying changes that I made in my mobx store class, for example logging values into console, which is not really developer friendly. I am open for any kind of solution that could impact the hot-reload
behaviour when changing the Store.ts
code. Here is my implementation for nextJs.
_app.tsx
import { StoreProvider } from 'components/configurator/StoreProvider';
function App({ Component, pageProps }: AppProps) {
return (
<StoreProvider {...pageProps}>
<Component {...pageProps} />
</StoreProvider>
);
}
export default App;
StoreProvider.tsx
import { createContext, useContext } from 'react';
import { CartStore } from 'shared/store';
let store;
export const StoreContext = createContext<CartStore>({} as CartStore);
export function useStore() {
const context = useContext(StoreContext);
if (context === undefined) {
throw new Error('useStore must be used within StoreProvider');
}
return context;
}
export function StoreProvider({ children, initialState: initialData }) {
const store = initializeStore(initialData);
return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>;
}
function initializeStore(initialData = null) {
const _store = store ?? new CartStore();
// If your page has Next.js data fetching methods that use a Mobx store, it will
// get hydrated here, check `pages/ssg.js` and `pages/ssr.js` for more details
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 (!store) store = _store;
return _store;
}
Store.ts
import { makeAutoObservable } from 'mobx';
import { enableStaticRendering } from 'mobx-react-lite';
import { ProductGroupData } from './APITypes';
// NextJS specific, don´t render server-side
enableStaticRendering(typeof window === 'undefined');
export interface ProductGroup extends ProductGroupData {}
export class CartStore {
productGroups: ProductGroup[] = [];
constructor() {
makeAutoObservable(this);
}
hydrate = (data) => {
if (!data) return;
this.productGroups = data.productGroups;
};
updateProductGroups = (productGroup: ProductGroup) => {
const packageAlreadyInStore = this.productGroups.find((x) => x.name === productGroup.name);
if (!packageAlreadyInStore) {
this.productGroups.push(productGroup);
} else {
this.productGroups = this.productGroups.filter((x) => x.name !== productGroup.name);
}
};
}
I figured it out for myself, now I am hydrating the StoreProvder
in the _app.tsx
by passing it from the pageProps
.
_app.tsx
import 'styles/global.css';
import type { AppProps } from 'next/app';
import { StoreProvider } from 'components/configurator/StoreProvider';
function App({ Component, pageProps }: AppProps) {
return (
<StoreProvider {...pageProps} hydrationData={pageProps.hydrationData}>
<Component {...pageProps} />
</StoreProvider>
);
}
export default App;
StoreProvider.tsx
import { createContext, useContext } from 'react';
import { CartStore } from 'shared/Store';
let store;
export const StoreContext = createContext<CartStore>({} as CartStore);
export function useStore() {
const context = useContext(StoreContext);
if (context === undefined) {
throw new Error('useStore must be used within StoreProvider');
}
return context;
}
export function StoreProvider({ children, hydrationData: hydrationData }) {
const store = initializeStore(hydrationData);
return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>;
}
function initializeStore(hydrationData = null) {
const _store = store ?? new CartStore();
// If your page has Next.js data fetching methods that use a Mobx store, it will
// get hydrated here, check `pages/ssg.js` and `pages/ssr.js` for more details
if (hydrationData) {
_store.hydrate(hydrationData);
}
// For SSG and SSR always create a new store
if (typeof window === 'undefined') return _store;
// Create the store once in the client
if (!store) store = _store;
return _store;
}