Front-End Insights

How to connect MobX with a react-router?

MobXProgrammingReact

My last blog post about the introduction to MobX was very popular on social media so I think the MobX topic must be very interesting for many of you. I did some research and noticed that many people are confused about how to connect MobX with a react-router… That’s why I decided to demystify it for you.

Don’t worry, it’s easy!

MobX with a react-router – the Redux like way

In the post about Redux I told you about the connect function and the Provider component. Let’s take a look at a part of that example again:

import { createStore } from 'redux';
import { connect, Provider } from 'react-redux';

const store = createStore(...);

... // the rest of the example in the post about Redux

const mapStateToProps = (state) => {
  return { counter: state.counter };
};
const mapDispatchToProps = (dispatch) => {
  return {
    onIncrement: () => dispatch({ type: 'INCREMENT' }),
    onDecrement: () => dispatch({ type: 'DECREMENT' })
  }
};
 
Counter = connect(mapStateToProps, mapDispatchToProps)(Counter);
 
render(
  <Provider store={store}>
    <Counter />
  </Provider>,
  document.getElementById('root')
);

Please bear in mind that this is only a part of the full example. If you want, see the full example in the mentioned article.

Redux’s connect function and Provider component

The most important thing in the above example was that we had to use the connect function to connect a React component to a Redux store. We also had to wrap the root component of the application in the Provider component to make the Redux store available to the connect function calls.

If we talk about a react-router used in the React + Redux application, we normally have to do the same with the routes configuration:

ReactDOM.render(
  <Provider store={store}>
    <Router history={history}>
      <Route path="/" component={App}>
      </Route>
    </Router>
  </Provider>,
  document.getElementById('app')
);

This way, the React component attached to the route has the store available.

The MobX way – Provider component

So, how do we use MobX with a react-router? There is no need to use the connect function, so how do we inject a store to all these route components? Well, luckily the ‘mobx-react’ library gives us its own Provider component… This is its description in the library documentation:

Provider is a component that can pass stores (or other stuff) using React’s context mechanism to child components. This is useful if you have things that you don’t want to pass through multiple layers of components explicitly.

As you can see, thanks to the Provider component we can pass the stores object to all the child components. That’s why this part will be very similar to the Redux one:

import { Provider } from 'mobx-react';
import usersStore from './stores/usersStore';
import itemsStore from './stores/itemsStore';

const stores = { usersStore, itemsStore };

ReactDOM.render(
  <Provider {...stores}>
    <Router history={history}>
      <Route path="/" component={App}>
      </Route>
    </Router>
  </Provider>,
  document.getElementById('app')
);

Please note that we simply combine all our stores into one object. Then we pass it as an argument of the Provider component using the spread operator. This is equivalent of this:

<Provider userStore={userStore} itemsStore={itemsStore}>

The MobX way – inject decorator

But this is not all. The ‘mobx-react’ library also provides the inject decorator. This is its definition:

inject can be used to pick up those stores (passed using Provider – author’s note). It is a higher order component that takes a list of strings and makes those stores available to the wrapped component.

This is how we use the inject decorator in the component:

class App extends React.Component {
  render () {
    return <ChildComponent />
  }
}

@inject('itemsStore') @observer
class ChildComponent extends React.Component {
  render() {
    return (
      <div className="index">
        {this.props.itemsStore.items.map((item, index) => {
          return <span key={index}>item.name</span>
        })}
      </div>
    );
  }
}

In the above example we used the inject decorator and gave it the name of the store (‘itemsStore’) as an argument. Thanks to this we can pick which store of all our stores will be available in this.props in this particular component.

Please note that the order of decorators matters! The observer decorator should be “inner” and the inject decorator “outer”.

MobX with a react-router – importing state directly

Apart from the described approach you can also avoid using the Provider component:

ReactDOM.render(
  <Router history={history}>
    <Route path="/" component={App}>
    </Route>
  </Router>
  document.getElementById('app')
);

Then you will have to import your stores in the container component:

import store from './stores/store';

@observer
class App extends React.Component {
  render() {
    return (
      <ChildComponent store={store} />
    );
  }
}

Personally I prefer the first approach but this might also be a good way of using MobX with a react-router. But then, please remember to strictly split your components into container and presentational ones. In this case, the ChildComponent in the above example should only render the state. All the manipulations should be done in the App component which is a “container” in this example. Even if the ChildComponent component has its own children, it shouldn’t pass the whole store into them.

Summary

These were two approaches for using MobX with a react-router. I hope they will be helpful to some of you. The first one is kinda similar to the way we deal with Redux and a react-router. But… I don’t think the second one is bad. Everything depends on your needs and preference.

Related Post

I recommend Nozbe

Simply Get Everything Done

Get your tasks and projects done thanks to Nozbe system and apps for the Mac, Windows, Linux, Android, iPad and iPhone.

If you want to know more about Nozbe and its capabilities, please take a look at my article about this great application.


  • Michael Romanoff

    Nice article. I just was exploring @inject decorator the other day. which was just introduced in mobx-react recently. It’s worth to mention how to validate propTypes for mobx store. MyComponent.wrappedComponent.propTypes = { providersStore: PropTypes.object.isRequired };

    • Thanks for good words and mentioning the propTypes – maybe I will update the article 😉