Managing State with MobX

Published Apr 23, 2018Last updated May 24, 2018
Managing State with MobX

From this post, you will learn what MobX is, what it is useful for, the benefits of MobX and some major MobX concepts. We will then go through a quick tutorial describing briefly how to use MobX in a react application.

What is MobX?

MobX is simply a state management library.

A primary concern related to building single page applications is having to deal with data changes over time (especially in a client-server application) and re-rendering based on these changes.

Here comes state management…

State management basically means managing the state of the application or data presented to the user at any given time.

To properly manage state, it is very important to be able to track:

  • Whether the state changes.
  • What the state was before the change.
  • Whether the state will change again

In single page applications, there will be interactions with the data at different times with the components. It is important to be able to handle these changes when they occur.

Why MobX?

With MobX, the application state is synchronized with your component by using a reactive virtual dependency state graph, internally. It is only updated when needed and is never stale. The following are reasons why you may want to have MobX in your application:

  • It is very simple to use and therefore speeds up development considerably.
  • With MobX, you do not need to normalize your data.
  • Modifying state is very straightforward. You simply write your intentions and MobX handles the rest.
  • MobX automatically tracks changes between states and derivations. As a developer, you might forget that changing some data would influence a seemingly unrelated component, but MobX does not.

Major MobX concepts

  • Observable State

    Observable capabilities are added to data structures, arrays, or class instances with the use of the observable decorator.

    import { observable } from “mobx”;
    
    class WorkoutStore {
      @observable completed = false;
    }
    

    Using observable can be likened to turning the object property to a cell in the spreadsheet, except that values are objects, arrays, and references and not primitive values.

  • Computed values

    They are values derived from state. Using computed decorator defines values that will be derived automatically when relevant data is modified.

    class WorkoutStore {
      @observable workouts = [];
      @computed get UncompletedWorkoutsCount() {
          return this.workouts.filter(workout => !workout.completed).length;
      }
    }
    

    Here UncompletedWorkouts is updated automatically when a workout is added or when any completed property is modified.

  • Reactions

    Reactions produce a side effect instead of producing a new output (like the case of computed values) when a new change occurs. You can make your stateless components reactive by adding the observer function/decorator from the mobx-react package.

    import React, {Component} from 'react';
    import ReactDOM from 'react-dom';
    import {observer} from 'mobx-react';
    
    @observer
    class AllWorkouts extends Component {
      render() {
        return 
          <div>
            <ul>
              {this.props.workoutList.workouts.map(workout =>
                  <Workout workout={workout} key={workout.id} />
              )}
            </ul>
            Workouts left: {this.props.workoutList.unfinishedWorkoutCount}
          </div>
      }
    }
    
    const Workout = observer(({workout}) =>
        <li>
          <input
            type="checkbox"
            checked={workout.finished}
            onClick={() => workout.finished = !workout.finished}
          />{workout.title}
        </li>
    )
    
    const store = new WorkoutList();
    ReactDOM.render(<AllWorkouts workoutList={store} />, document.getElementById('mount'));
    

    React components are turned into derivations of the data they render with observer. MobX ensures that the components are re-rendered when needed.

  • Actions

    Any piece of code that tries to alter the state is an action. It takes in a function and returns a function. Functions that perform look-ups, filters, etc. should not be marked as actions. Actions should only be used on functions that modify state. Actions are usually marked with the @action decorator.

Quick tutorial

Let’s set up a quick React application called FriendList with MobX.

  • We start with setting up the React projectScreen Shot 2018-04-18 at 6.27.45 PM.png
    Screen Shot 2018-04-18 at 6.34.08 PM.png
  • Run yarn start and view the app as shown:
    Screen Shot 2018-04-18 at 6.35.27 PM.png
  • Now to use decorators, we need to modify the configuration of the React app, so first of all we run:
    Screen Shot 2018-04-18 at 6.40.31 PM.png

This basically moves the build dependencies into our project and allows for customization.

  • Next, we run:
    Screen Shot 2018-04-18 at 6.51.31 PM.png
    Go to package.json, look for the babel section, and add ‘transform-decorators-legacy’ plugin.
    Screen Shot 2018-04-18 at 6.53.41 PM.png
    By doing these two steps, we are able to use decorators in the application.
  • Next, we install mobx-react and mobx:
    Screen Shot 2018-04-18 at 6.58.27 PM.png

Now that we have MobX set up, let’s have some content:

  • Go to src folder and create a stores folder.
    In MobX, we can have different stores that handle state for one piece of the application. Dor this demo, we would create one store called FriendStore.
    Screen Shot 2018-04-19 at 1.43.18 PM.png

  • Up next, we want to fill up our store:

    • Import observable, action, and computed from mobx.
    • Create a class called FriendStore that is made up of a property called friends, which is an observable (things that we want to keep track of).
    • We create an action called addFriend.
    • Finally, create a computed property called friendCount that returns the number of friends.
      Screen Shot 2018-04-19 at 10.39.37 AM.png
  • Next, we go into the index.js file:

    • Import Provider from mobx.
    • Wrap app component with Provider, then render the Root constant created, which contains the Provider and App.
    • Import FriendStore and pass as props to the Provider.
      Screen Shot 2018-04-19 at 1.50.00 PM.png

Finally, time to show something to the user!

We want to have an input field to add friend and a list to show the friends added:

  • Go to App.js.
  • We import inject and observer from mobx-react.
  • With the decorators (inject and observer), we inject the FriendStore in the application and make the component an observer (which basically watches the store for when data changes).
  • We create a form to enter and submit a friend.
    Screen Shot 2018-04-19 at 1.59.28 PM.png

and Voila..
Screen Shot 2018-04-19 at 10.42.45 AM.png

I hope this has been helpful in getting you up to speed with MobX. Feel free to ask questions in the comment section.

Discover and read more posts from Susan Adelokiki
get started