5

I am trying to access my store from every component page I have, so I followed the following tutorial in order to connect React Router & MobX.

http://frontendinsights.com/connect-mobx-react-router/

However, I am facing a problem at The MobX way – Provider component.

This is the code exmaple:

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')
);

I tried to do the same in index.js

import React from 'react'
import { render } from 'react-dom'
import { Router, hashHistory, Route, IndexRedirect } from 'react-router'
import App from './webapp/App'
import Home from './components/pages/Home'
import Dogs from './components/pages/Dogs'
import Cats from './components/pages/Cats'
import Provider from 'mobx-react'
import RootStore from './webapp/stores'

const store = RootStore

render((
  <Provider rootStore={store}>
    <Router history={hashHistory}>
        <Route path="/" component={App}>
          <IndexRedirect to="/home" />
          <Route path="/home" component={Home}/>
          <Route path="/dogs" component={Dogs}/>
          <Route path="/cats" component={Cats}/>
        </Route>
      </Router>
    </Provider>
), document.getElementById('app'))

However, because of <Provider/>, I am getting an error:

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).

Why am I getting that? It should work doesn't it?

Thanks for any help !

Emixam23
  • 3,854
  • 8
  • 50
  • 107

1 Answers1

2

If it's a web app, react-router-dom should be used.

Here is the correct way to inject store with Provider https://github.com/mobxjs/mobx-react#observer

I wrote a solution for your code without using decorator, so it supports create-react-app:

import React, { Component } from 'react';
import { Provider, Observer } from 'mobx-react';
import { observable } from 'mobx';
import { BrowserRouter, Switch, Route, Link, Redirect } from 'react-router-dom';

const myStore = observable({
  home: 'Home',
  cat: 'Cat',
});

const Home = () => (
  <Observer 
    inject={stores => ({ myStore : stores.myStore })}
    render={props => (<section><h1>{props.myStore.home}</h1></section>)}
  />
);

const Cat = () => (
  <Observer 
    inject={stores => ({ myStore : stores.myStore })}
    render={props => (<section><h1>{props.myStore.cat}</h1></section>)}
  />
);

class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <Provider myStore={myStore}>
          <div className="App">
            <header className="App-header">
              <nav>
                <ul>
                  <li><Link to="/home">HOME</Link></li>
                  <li><Link to="/cat">CAT</Link></li>
                </ul>
              </nav>
            </header>
            <Switch>
              <Route path='/home' exact component={Home} />
              <Route path='/cat' exact component={Cat} />
              <Redirect from="/" to="/home" />
            </Switch>
          </div>
        </Provider>
      </BrowserRouter>
    );
  }
}

export default App;

All the components are in App.js file. There is no change in default index.js from create-react-app.

Note:
The another way to doing this, it's to simply create a singleton class for the store and use export default new Store() to make it available to all components. The class itself doesn't have to be observable, but its properties do.

FisNaN
  • 2,517
  • 2
  • 24
  • 39