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 aworkout
is added or when anycompleted
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
- Run
yarn start
and view the app as shown:
- Now to use decorators, we need to modify the configuration of the React app, so first of all we run:
This basically moves the build dependencies into our project and allows for customization.
- Next, we run:
Go topackage.json
, look for thebabel
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-react
andmobx
:
Now that we have MobX set up, let’s have some content:
-
Go to
src
folder and create astores
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 calledFriendStore
.
-
Up next, we want to fill up our store:
- Import
observable
,action
, andcomputed
frommobx
. - 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
-
Next, we go into the
index.js
file:- Import
Provider
frommobx
. - 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
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
andobserver
frommobx-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.
and Voila..
I hope this has been helpful in getting you up to speed with MobX. Feel free to ask questions in the comment section.