Introduction to MobX 4 for React/Redux Developers
Tags: mobx, react, mobxreact
Published: 2018-03-17 02:19:23

---
title: Introduction to MobX 4 for React/Redux Developers
published: true
description: an introduction to mobx 4 for people coming from react and redux
tags: mobx, react, mobx-react
---

MobX uses the "magic" of observables to manage state and side effects. This not only has a learning curve but is a different programming paradigm altogether, and there is not a lot of up-to-date training material on how to use React with Mobx, while there is far, far more content on using React with Redux. 

In this intro we will progressively build up a simple app that pings a mock API to see how MobX works with React, and then make a MobX + React Kanban board to show off the power of MobX! 

![it will look like this](https://user-images.githubusercontent.com/6764957/37550034-5a31617a-295d-11e8-8799-60c6f57bde0a.gif)

How we will proceed:

- **Example A**. Build a basic app that lets you type an text **Input** that is reflected in a **Display**. _We show the basics of establishing `observable`s and `observer` components._
- **Example B**. We split up the **Input** and **Display** into siblings to simulate a more complex app. We also introduce async state updating by pinging a mock API. _To do this we use the `mobx-react` `Provider` to put MobX state into React context to demonstrate easy sibling-to-sibling or sibling-to-parent communication similar to `react-redux`._
- **Example C**: We add a secondary **Display** to our app. _Demonstrates the usefulness of `computed` variables (a Mobx concept)._
- **Example D**: We scale our app up to do an arbitrary number of Displays. _Demonstrates using arrays and maps for our MobX state._
- **Example E**: Tune up and Cleanup! _We add the MobX dev tools, put our whole app in `useStrict` mode and explain the formal use of MobX `action`s and `transaction`s for better app performance._

This tutorial will use [the recently released MobX 4](https://medium.com/@mweststrate/mobx-4-better-simpler-faster-smaller-c1fbc08008da) and MobX-React 5. A lot of people associate MobX with decorators, which are only a [stage 2 proposal](https://www.github.com/tc39/proposal-decorators). That (rightfully) causes hesitation for some people, but MobX 4 introduces non-decorator based syntax so we don't have that excuse anymore! However; for tutorial writers this is a problem, because you have to decide to either teach one or the other or both. To resolve this, every example here will use the non decorator syntax as the primary version, but will have a clone that uses decorators to show the equivalent implementation (e.g. Example A vs Decorators A).

_Note to Reader: There is not an attempt at recommending MobX over Redux or vice versa. This is solely aimed at factually introducing core MobX concepts for people like myself who were only familiar with Redux. I will attempt to draw some conclusions but reasonable people will disagree. Additionally, Michel Weststrate has stated repeatedly that [both libraries address completely different requirements and values](https://codeburst.io/the-curious-case-of-mobx-state-tree-7b4e22d461f)._

# EXAMPLE A1: React + MobX

Here is our very basic app using React + MobX:

```js
import { decorate, observable } from "mobx";
import { observer } from "mobx-react";

const App = observer(
  class App extends React.Component {
    text = ""; // observable state
    render() {
      // reaction
      return (
        <div>
          Display: {this.text} <br />
          <input
            type="text"
            onChange={e => {
              this.text = e.target.value; // action
            }}
          />
        </div>
      );
    }
  }
);
decorate(App, { text: observable });
```

_([Example A1](https://codesandbox.io/s/236xqx6qn0), [Decorators A1](https://codesandbox.io/s/n7ynrm72op))_

You can see here that `observer` connects the observable `text` property of `App` so that it rerenders whenever you update `text`. 

While this is nice, it really isn't any different from using `state` and `setState`. If you have React you don't need MobX just to do this.

# EXAMPLE A2: So what?

Let's try separating the concerns of state and view model:

```js
// this deals with state
const appState = observable({
  text: "" // observable state
});
appState.onChange = function(e) { // action
  appState.text = e.target.value;
};

// this deals with view
const App = observer(
  class App extends React.Component {
    render() { // reaction
      const { text, onChange } = this.props.store;
      return (
        <div>
          Display: {text} <br />
          <input type="text" onChange={onChange} />
        </div>
      );
    }
  }
);

// you only connect state and view later on...
// ... 
<App store={appState} />
```

_([Example A2](https://codesandbox.io/s/n995rqm67j), [Decorators A2](https://codesandbox.io/s/wqowjv9rvw))_

Here the `store`:

- is explicitly passed in as a prop (we will use the `Provider` pattern later)
- brings its own action handlers along with it (no separate reducers to import)

# EXAMPLE A3: But that's not OO

Look at this part of the above code.

```js
const appState = observable({
  text: "" // observable state
});
appState.onChange = function(e) { // action
  appState.text = e.target.value;
};
```

Yeah, I dont like that. The method isn't encapsulated within the observable. Can we make it more object oriented?

```js
// import { decorate } from 'mobx'

class State {
  text = ""; // observable state
  onChange = e => (this.text = e.target.value); // action
};
decorate(State, { text: observable });
const appState = new State()
```

_([Example A3](https://codesandbox.io/s/5xmo5n513n), [Decorators A3](https://codesandbox.io/s/wo8k6j190k))_

ahh. much better (especially the Decorators example where you don't need to use `decorate`)!

# EXAMPLE B1: But I hate prop drilling!

Just like `react-redux` lets you put your store in a `Provider`, `mobx-react` also has a `Provider` that works in the same way. We will refactor our Display and our Input components into sibling apps:

```js

import { inject, observer, Provider } from "mobx-react";

class State {
  text = ""; // observable state
  onChange = e => (this.text = e.target.value); // action
}
decorate(State, { text: observable });
const appState = new State();

const Display = inject(["store"])(
  observer(({ store }) => <div>Display: {store.text}</div>)
);

const Input = inject(["store"])(
  observer(
    class Input extends React.Component {
      render() {
        // reaction
        return <input type="text" onChange={this.props.store.onChange} />;
      }
    }
  )
);

// look ma, no props
const App = () => (
  <React.Fragment>
    <Display />
    <Input />
  </React.Fragment>
);

// connecting state with context with a Provider later on...
// ...
<Provider store={appState}>
    <App />
  </Provider>
```

_([Example B1](https://codesandbox.io/s/n71y76okym), [Decorators B1](https://codesandbox.io/s/mjz6jlyj0j))_

Note that if I were to add a -second- store, I could simply define another `observable`, and pass it in to `Provider` as another prop, which I can then call from any child. No more redux style `combineReducers`!

Using a Provider also helps avoid creating global store instances, something that is strongly advised against in [MobX React Best Practices](https://medium.com/dailyjs/mobx-react-best-practices-17e01cec4140).

_MobX 4 Note: If you just try to use the old MobX `observer(['store'])` shorthand, which was always synonymous with `observer` + `inject(['store'])`, you will get a very nice deprecation warning to not do that anymore._

I found this inject/observer syntax a bit fiddly, so this is a nice little utility function you can define to type less:

```js
const connect = str => Comp => inject([str])(observer(Comp));
```

Hey! that's like our good friend `connect` from `react-redux`! The API is a little different, but you can define whatever you want 🤷🏼‍♂️.

# EXAMPLE B2: Ok but what about async

Well for async API fetching we have a few choices. We can go for:

- `mobx-thunk`
- `mobx-observable`
- `mobx-saga`
- and about 300 other options.

They're all special snowflakes and we can't wait to see what you decide on!

_pause for rage quit..._

Ok if you couldnt tell, I was kidding. Using observables means you can "just" mutate the observables and your downstream states will react accordingly. You might have observed that I have been annotating the code examples above with `// reaction`, `// action`, and `// observable state`, and they mean what they normally mean in English. We'll come back to this.

Back to code! Assume we now have an async API called `fetchAllCaps`. This is a `Promise` that basically capitalizes any text you pass to it, after a 1 second wait. So this simulates a basic request-response flow for any async action you want to take. Let's insert it into our example so far!

```js
class State {
  text = ""; // observable state
  onChange = e => {
    // action
    this.text = e.target.value;
    fetchAllCaps(e.target.value).then(val => (this.text = val));
  };
}
decorate(State, { text: observable });
const appState = new State();
```

_([Example B2](https://codesandbox.io/s/nn957yx004), [Decorators B2](https://codesandbox.io/s/mjz6jlyj0j))_

Well that was... easy?

Note that here we are using the [public class fields](https://tc39.github.io/proposal-class-public-fields/) stage 2 feature for that `onChange` property, while not using decorators, which are also stage 2. I decided to do this because public class fields are so widespread in React (for example, it comes with `create-react-app`) that you likely already have it set up or can figure out how to set it up in Babel if you need to).

---

# CONCEPT BREAK! Time to recap!

We've come this far without discussing core MobX concepts, so here they are:

- Observable state
- Actions
- Derivations (Reactions and Computed values)

In our examples above we've already used **observable states** as well as defined **actions** that modify those states, and we have used `mobx-react`'s `@observer` to help bind our React components to **react** to changes in state. So that's 3 out of 4. Shall we check out Computed values?

---

## EXAMPLE C: Computed Values

**Computed values** are essentially **reactions** without side effects. Because [Observables are lazy](https://github.com/ReactiveX/rxjs/blob/master/doc/observable.md) by default, MobX is able to defer calculations as needed. They simply update whenever the **observable state** updates. Another way of phrasing it, computed values are **derived** from observable state. 

Let's add a computed value that just reverses whatever is in `text`:

```js
class State {
  text = "";
  get reverseText() {
    return this.text
      .split("")
      .reverse()
      .join("");
  }
  onChange = e => {
    // action
    this.text = e.target.value;
    fetchAllCaps(e.target.value).then(val => (this.text = val));
  };
}
decorate(State, { text: observable, reverseText: computed });
const appState = new State();

// lower down...
const Display2 = inject(["store"])(
  observer(({ store }) => <div>Display: {store.reverseText}</div>)
);
```

_([Example C1](https://codesandbox.io/s/jnmz0v2189), [Decorators C1](https://codesandbox.io/s/qk933p79j4))_

Cool! It "just works" (TM) !

A fair question to have when looking at this is: **why bother**?? I can always put synchronous business logic in my React `render` function, why have computed values at the appState level at all?

That is a fair criticism in this small example, but imagine if you rely on the same computed values in **multiple** places in your app. You'd have to copy the same business logic all over the place, or extract it to a file and then import it everywhere. Computed values are a great way to model derivations of state by *locating them nearer to the state* rather than nearer to the *view*. It's a minor nuance but can make a difference at scale.

By the way, [vue.js](https://vuejs.org/v2/guide/computed.html) also has computed variables, while [Angular](https://stackoverflow.com/questions/43710642/does-angular-have-the-computed-property-feature-like-in-vue-js) just uses them implicitly.

## EXAMPLE D1: Observable Arrays

MobX can make basically anything observable. Let me quote [the docs](https://mobx.js.org/refguide/observable.html):

1. If value is an ES6 Map: a new [Observable Map](https://mobx.js.org/refguide/map.html) will be returned. Observable maps are very useful if you don't want to react just to the change of a specific entry, but also to the addition or removal of entries.
2. If value is an array, a new [Observable Array](https://mobx.js.org/refguide/array.html) will be returned.
3. If value is an object without prototype, all its current properties will be made observable. See [Observable Object](https://mobx.js.org/refguide/object.html)
4. If value is an object with a prototype, a JavaScript primitive or function, a [Boxed Observable](https://mobx.js.org/refguide/boxed.html) will be returned. MobX will not make objects with a prototype automatically observable; as that is the responsibility of its constructor function. Use extendObservable in the constructor, or @observable in its class definition instead.

In the examples above we have so far been making [Boxed Observables](https://mobx.js.org/refguide/boxed.html) and [Observable Objects](https://mobx.js.org/refguide/object.html), but what if we wanted to make an array of observables?

[Observable Arrays](https://mobx.js.org/refguide/array.html) are array-*like* objects, not actual arrays. This can bite people in the behind, particularly when passing data to other libraries. To convert to a normal JS array, call `observable.toJS()` or `observable.slice()`.

But most of the time you can just treat Arrays as arrays. Here's a very simple Todo app using an observable array:

```js
class State {
  text = ["get milk"]; // observable array
  onSubmit = e => this.text.push(e); // action
}
decorate(State, { text: observable });
const appState = new State();

const Display = inject(["store"])(
  observer(({ store }) => (
    <ul>Todo: {store.text.map(text => <li key={text}>{text}</li>)}</ul>
  ))
);

const Input = observer(
  ["store"],
  class Input extends React.Component {
    render() {
      // reaction
      return (
        <form
          onSubmit={e => {
            e.preventDefault();
            this.props.store.onSubmit(this.input.value);
            this.input.value = "";
          }}
        >
          <input type="text" ref={x => (this.input = x)} />
        </form>
      );
    }
  }
);

const App = () => (
  <React.Fragment>
    <Display />
    <Input />
  </React.Fragment>
);
```

_([Example D1](https://codesandbox.io/s/p0m2l15vm), [Decorators D1](https://codesandbox.io/s/o9y428q9zq))_

note that "just `push`" just works!

## Example D2: Observable Maps

What's the difference between Observable Objects (what we used in Examples A, B, and C) and [Observable Maps](https://mobx.js.org/refguide/map.html)? Well, its the same difference between Plain Old Javascript Objects and [ES6 Maps](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map). I will quote the MobX doc in explaining when to use Maps over Objects:

> Observable maps are very useful if you don't want to react just to the change of a specific entry, but also to the addition or removal of entries.

So if we want to have a bunch of Todo lists, where we can add new todo lists, this is the right abstraction. So if we take that App from Example D1, rename it to `TodoList` and put it in `todolist.js` with some other superficial tweaks, then on `index.js`, we can do this:

```js
// index.js
const connect = str => Comp => inject([str])(observer(Comp)); // helper function

const listOfLists = observable.map({
  Todo1: new TodoListClass(),
  Todo2: new TodoListClass()
  // observable map rerenders when you add new members
});
const addNewList = e => listOfLists.set(e, new TodoListClass());

const App = connect("lists")(
  class App extends React.Component {
    render() {
      const { lists } = this.props;
      return (
        <div className="App">
          <span />
          <h1>MobX Kanban</h1>
          <span />
          {Array.from(lists).map((k, i) => (
            <div key={i}>
              {/*Provider within a Provider = Providerception */}
              <Provider todolist={k}>
                <TodoList />
              </Provider>
            </div>
          ))}
          <div>
            <h3>Add New List</h3>
            <form
              onSubmit={e => {
                e.preventDefault();
                addNewList(this.input.value);
                this.input.value = "";
              }}
            >
              <input type="text" ref={x => (this.input = x)} />
            </form>
          </div>
        </div>
      );
    }
  }
);
```

_([Example D2](https://codesandbox.io/s/x3pl9p042w), [Decorators D2](https://codesandbox.io/s/ryonwww274))_

And hey presto! We have a Kanban board (an expandable list of lists)!

![kanban](https://user-images.githubusercontent.com/6764957/37550034-5a31617a-295d-11e8-8799-60c6f57bde0a.gif)

This was enabled by the dynamically expanding ability of that `listOfLists` which is an Observable Map. To be honest, you could probably also use Arrays to achieve this but if you have a use case that is better suited for demonstrating Observable Maps, please **let me know in the comments below.**

# Example E1: MobX Dev Tools

[Redux dev tools](https://github.com/gaearon/redux-devtools/blob/master/docs/Walkthrough.md) are (rightfully) an important part of Redux's value, so let's check out [MobX React dev tools](https://github.com/mobxjs/mobx-react-devtools)!

```js
import DevTools from 'mobx-react-devtools'; // npm install --save-dev mobx-react-devtools

// somewhere within your app...
        <DevTools />
```

_([Example E1](https://codesandbox.io/s/7m0xoy9336), [Decorators E1](https://codesandbox.io/s/oo2n902jr5))_


You can see the three icons pop up:

- Visualize rerenders
- Audit the dependency tree
- Log everything to console (use Browser console not Codepen console)

You can't do time travel but this is a pretty good set of tools to audit any unexpected state changes going on in your app.

# Stay tuned...

There is a blocking bug with `mobx-dev-tools` and `mobx` 4: <https://github.com/mobxjs/mobx-react-devtools/issues/86> and I will finish this out  when the bug is fixed.


However in the mean time you can check out how to explicitly define `actions` so that MobX can batch your state changes into `transaction`s, which is a big performance saver:

<https://mobx.js.org/refguide/action.html>


Notice how we were able to do all our demos without using the `action`s - MobX has a (poorly) documented strict mode (formerly `useStrict`, now `configure({enforceActions: true});`) - see [the MobX 4 docs](https://github.com/mobxjs/mobx/blob/gh-pages/docs/refguide/api.md#configure). But we need the dev tools to really show the benefits for our example app.


## Acknowledgements

This introduction borrows a lot of code and structure from [Michel Weststrate's egghead.io course](https://egghead.io/courses/manage-complex-state-in-react-apps-with-mobx), but updates the 2 year old course for the current Mobx 4 API. I would also like to thank my employer for allowing me to learn in public.

The examples here were done with the help of [Javid Askerov](http://twitter.com/askerovlab), [Nader Dabit](http://twitter.com/dabit3), and [Michel](http://twitter.com/mweststrate).

## Other Tutorials and Further Reading

Other recent guides
- [MobX + React Native](https://dev.to/satansdeer/react-native-mobx-tutorial---part-1--2df0)
- [MobX + React best practices](https://medium.com/dailyjs/mobx-react-best-practices-17e01cec4140)
- [MobX 4 launch blogpost](https://medium.com/@mweststrate/mobx-4-better-simpler-faster-smaller-c1fbc08008da)

Docs
- [MobX docs - common pitfalls and best practices](https://mobx.js.org/best/pitfalls.html)
- [MobX changelog - be very careful on v3 vs v4 changes](https://github.com/mobxjs/mobx/blob/master/CHANGELOG.md)
- [official MobX+React 10 minute guide](https://mobx.js.org/getting-started.html)

Older
- [one developer's pros and cons comparison of redux vs mobx](https://dannyherran.com/2017/03/react-redux-mobx-takeaways/)
- [Adam Rackis' old evaluation of MobX](https://medium.com/@adamrackis/a-redux-enthusiast-tries-mobx-af675f468c11)

Related libraries to explore
- [MobX state tree](https://github.com/mobxjs/mobx-state-tree) and associated [blogpost](https://codeburst.io/the-curious-case-of-mobx-state-tree-7b4e22d461f)

## Contribute

What other current (<1yr) resources should I include in this guide? Have I made any mistakes? Let me know below!