Managing State with MobX

susan adelokiki
6 min readJun 14, 2018

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 project using the create-react-app package
yarn install create-react-app
create-react-app friend list
  • Run yarn start and view the app as shown:
yarn start
  • Now to use decorators, we need to modify the configuration of the React app, so first of all we run:
yarn run eject

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

  • Next, we run:
yarn add babel-plugin-transform-decorators-legacy

Go to package.json, look for the babel section, and add ‘transform-decorators-legacy’ plugin.

By doing these two steps, we are able to use decorators in the application.

  • Next, we install mobx and mobx-react
yarn add mobx mobx-react

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. For this demo, we would create one store called FriendStore.
  • 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.

import { observable, action, computed } from "mobx";class FriendStore {
@observable friends = [];
@action addFriend(friend) {
this.friends.push(friend);
}
@computed get friendCount() {
return this.friends.length;
}
}const store = new FriendStore();
export default store;
  • 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.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { Provider } from 'mobx-react';
import FriendStore from './stores/FriendStore';
const Root = (
<Provider FriendStore={FriendStore}>
<App/>
</Provider>
)
ReactDOM.render(Root, document.getElementById('root'));
registerServiceWorker();

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.
import React, { Component } from 'react';
import { inject, observer } from 'mobx-react';
@inject('FriendStore')
@observer
class App extends Component { handleSubmit = (e) => {
e.preventDefault();
const friend = this.friend.value;
this.props.FriendStore.addFriend(friend);
this.friend.value = '';
}
render() {
const {FriendStore} = this.props;
return (
<div className="App">
<h2>You have {FriendStore.friendCount} friends.</h2>
<form onSubmit={e => this.handleSubmit(e)}>
<input type="text" placeholder="Enter friend" ref={input => this.friend = input}/>
<button>Add Friend</button>
</form>
<ul>
{FriendStore.friends.map(friend => (
<li key={friend}>{friend}</li>
))}
</ul>
</div>
);
}
}
export default App;

You may encounter an experimental Decorators warning if you are using VSCode. To cater for this, simply create a tsconfig.json file in the root directory of your project and include the following options and then restart VSCode.

{
"compilerOptions": {
"experimentalDecorators": true,
"allowJs": true
}
}

Finally, run yarn start

and Voila..

Here is the link to the github repo.

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

--

--