Tholle
Tholle

Reputation: 112777

Create a new MobX store instance for a React function component

When using MobX with React you can create a new Store instance on a class component instance like so:

const { extendObservable } = mobx;
const { Observer } = mobxReact;

class Store {
  constructor() {
    console.log("Created a store");
    extendObservable(this, {
      count: 0
    });
  }
}

class App extends React.Component {
  store = new Store();

  render() {
    const { store } = this;

    return (
      <Observer>
        {() => <button onClick={() => ++store.count}>{store.count}</button>}
      </Observer>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/[email protected]/lib/mobx.umd.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/index.min.js"></script>

<div id="root"></div>

When translating this to a function component it still works, but a new Store instance is created every render, which will not be used. This is not only wasteful, but can have undesired behaviour if the constructor contains additional logic.

const { extendObservable } = mobx;
const { observer, useObservable } = mobxReact;

class Store {
  constructor() {
    console.log("Created a store");
    extendObservable(this, {
      count: 0
    });
  }
}

const App = observer(() => {
  const store = useObservable(new Store());
  
  return <button onClick={() => ++store.count}>{store.count}</button>
});

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/[email protected]/lib/mobx.umd.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/index.min.js"></script>

<div id="root"></div>

Is there a way to just create one single Store instance on first render in a function component?

Upvotes: 3

Views: 2244

Answers (1)

Tholle
Tholle

Reputation: 112777

Instead of using the useObservable hook we can use the useState hook with a function that returns a new Store as argument. This function will only be invoked once on first render which will make it so only one Store instance is ever created.

const { useState } = React;
const { extendObservable } = mobx;
const { observer, useObservable } = mobxReact;

class Store {
  constructor() {
    console.log("Created a store");
    extendObservable(this, {
      count: 0
    });
  }
}

const App = observer(() => {
  const [store] = useState(() => new Store());
  
  return <button onClick={() => ++store.count}>{store.count}</button>
});

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/[email protected]/lib/mobx.umd.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/index.min.js"></script>

<div id="root"></div>

Upvotes: 3

Related Questions