1

I try to enable HMR on my project with typescript and webpack 2 but whenever I make a change I see the following output in the logs and the store is reset to its original values(discards state)

index.js:832 MobX Provider: Provided store 'appStore' has changed. Please avoid replacing stores as the change might not propagate to all children

The UI is refreshed partially after loading the hot update bundle which is good and expected but since the store lost its state, the UI is not the expected one.

What is the right pattern for keeping the state of mobx stores across HMR updates?

Currently the coode looks like the following:

const uiStore = new UiStore();
const appStore = new AppStore();

function render() {
  ReactDOM.render(
    <AppContainer>
    <Provider appStore={appStore} uiStore={uiStore}><App/></Provider>
  </AppContainer>, document.getElementById('root'))
}

const hot = (module as any).hot
if (hot) 
  hot.accept(() => {
    render()
  })
render()
David Schumann
  • 13,380
  • 9
  • 75
  • 96
yesil
  • 697
  • 1
  • 9
  • 19

2 Answers2

2

The problem was that after every hot reload, my index file that was referencing App component was re-required by the webpack on the client side and this was destroying the uiStore and appStore objects that was initialised in the index file. Declaring the store as a member of the window object has solved the problem. The stores now survive across hot module replacements.

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {AppContainer} from 'react-hot-loader';
import {observable} from 'mobx';
import {Provider} from 'mobx-react';

import {AppStore, UiStore, Stores} from './types/index';
import App from './components/App';
import './index.css';
declare var stores:Stores;

(window as any).stores = (window as any).stores || new Stores(new UiStore(), new AppStore());
function render() {
  ReactDOM.render(
    <AppContainer>
    <App {...stores} />
  </AppContainer>, document.getElementById('root'));
}

const hot = (module as any).hot
if (hot) 
  hot.accept(() => {
    render();
  })

render();
yesil
  • 697
  • 1
  • 9
  • 19
0

Each time you reload new page from another, your top component might be re-rendered which cause call

const uiStore = new UiStore();
const appStore = new AppStore();

each times.

this might be complained by mobx because you are replacing whole stores with new instance, which is not intended by Mobx.

Might be better if you create uiStore, appStore as a state, which still remain renders new pages.

dante
  • 933
  • 4
  • 16
  • 39