Start modelling your app today.

Get started for free

What's this?

Introduction to MobX

This article provides an introduction to MobX, the clientside observable framework used in Reactbot.


What is Mobx.

MobX is an observable framework for Javascript which allows for an implementation of the observer pattern.

There are 5 main features of MobX that are key to understanding how MobX works. These are observerable, reaction, action, autorun, and computed.

observable, action and reaction

Observables, actions and reactions are best demonstrated together since their functionality relies on each other. Take this code example:

import { action, observable, reaction } from 'mobx';

// A class to store some data inside
class Data {
    @observable
    value = 0;

    @action
    incrementValue = () => this.value += 1;

    constructor() {
        // Create a reaction that listens to the value property changing
        // and log a message to the console when that happens
        reaction(() => this.value, () => console.log('Value Changed'));
    }
}

// Create a new instance of the class
const myData = new Data();

// After this function is called, 'Value Changed' will be printed to the console
myData.incrementValue();

As an overview of what is occurring above, an observable is a variable we can store data that is going to be observed.

An action is a function which can change observable data.

A reaction is something that occurs once an observable has changed so we can perform side effects. reaction is a function which takes 2 functions as arguments. The first function returns what value should be observed and the second function performs a side effect when the observed value changes.

computed

A computed field is a handy way of abstracting derived state. A computed field is represented as a getter function in Javascript. This type of function takes no arguments and should have no side effects. As an example building on the code above.

class ComputedData extends Data {
    @computed
    get doubleValue() {
        return this.value * 2;
    }
}

One special property of a computed field is when it is used in a reaction the value of the computed field will be cached and not recomputed so long as the observables it is computed off do not change. For example

class NewData {
    @observable
    first = 1;

    @observable
    second = 1;

    @computed
    get doubleSecond() {
        return this.second * 2;
    }

    @action
    incrementFirst = () => {
        this.first += 1;
    }

    constructor() {
        reaction(() => this.first, () => console.log(this.doubleSecond));
    }
}

const data = new NewData();

data.incrementFirst(); // The value of doubleSecond will be computed and printed to the console
data.incrementFirst(); // The cached value of doubleSecond will be printed to the console

autorun

autorun is a special type of reaction that will run some side effect based on what values are used in the side effect. For example, building off the first code snippet.

const data = new Data();

// This function will run once when the autorunner is first set up.
autorun(() => {
    console.log('The new value is ' + data.value);
});

data.incrementValue(); // This will result in the above message being printed again with the new value.

One caveat of autorun is that it can only observe values that are used. If an observable is not used in the autorun function then MobX will not know to observe it. For example:

const data = new Data();

// Create an autorunner that won't observe anything
// Even though data.value is observable, it is not used and therefore it will not be observed
autorun(() => {
    if (false) {
        console.log(data.value);
    }
});

data.incrementValue(); // No message will be printed since no observable was used in the initial running of the function.

React and MobX

Now that we have an idea of how MobX works, we can cover how MobX integrates with React and how we can use it to build reactive user interfaces. Lets construct a MobX powered component:

@observer
class MyFirstObserver extends React.Component {
    @observable
    value = 0;

    @action
    incrementValue = () => this.value += 1;

    render() {
        return (
            <div>
                <span>The value is {this.value}</span>
                <button onClick={this.incrementValue}>Increase Me!</button>
            </div>
        );
    }
}

You can see at the top of the component we have declared it with an @observer decorator. This means the component will rerender itself when any observable values that are used in the render function change. This means since we use this.value in the render function, the component will be automatically rerendered when the button is clicked and invokes the action function callback.

It is important to note the semantics of an observer component is the same as autorun. If a value is not used in the first run of a render function then it will not be observed by the observer component. For example take the following render function:

render() {
    if (false) {
        return <h3>{this.value}</h3>;
    }

    return <h3>Hello world</h3>;
}

Since this.value is not actually used in the call to render then it will not be tracked and the component will not update if it is changed.

Often in our react code we use MobX observables in any case where we would use react state and generally don’t need to call setState in our code.


Start modelling your app today.