In this tutorial, we are going to learn about Mobx which is an easier and simpler alternative to Redux (at least in my opinion).
For this tutorial, we are going to use custom react script which is very similar to Create React App(CRA). CRA allows you to setup React projects without having to do Webpack and Babel configurations but in CRA we cannot use Decorators, so we are going to use Custom React Script which allows us to use Decorators in CRA.
First, let’s install create-react-app you can do that by running the command
npm install -g create-react-app
create-react-app react-mobx-app — scripts-version custom-react-scripts
here react-mobx-app is a name of our project.
Then, we will install two libraries mobx and mobx-react(mobx binding for React) by using either of following two commands
yarn add mobx mobx-react or npm install mobx mobx-react.
You might be thinking, why do we need mobx in the first place? Doesn’t React have its own state management?
Well, it does, but there are few problems with it.
It’s not possible to share states with other components using Default React State Management.
With too many states, it becomes very difficult to maintain them in long run.
You might have heard of ‘props drilling’ issue i.e if you want to pass states from parent component to its deeply nested child component, it becomes very difficult to manage all the props since we need to pass props to all components that come in between parent and child components.
These can be solved using Mobx. So let’s dive deeper into Mobx and understand its core concepts.
Core concepts in Mobx
First, we are going to learn about observer and observable.
I have opened a react-mobx-app project in VSCode as you can see here
In `scripts` object, there is a start script which you can run by typing yarn run start in the command line to start the development server.
In Index.js file, let’s create our first mobx state
In above code, we are importing `observable` from `mobx` package which gives us the ability to create a `state`.
We then, simply pass an object to an observable function which gives us Mobx state (observable object) we can use it to pass to any component we want.
Here, I have simply created a sample Counter component which accepts `appState` as props and renders `count` property on it.
Finally, we are rendering counter component to the screen and also passing `appState` as props to `Counter` component.
In the browser, you will see zero counts on screen. With this, we know how to create a state, let’s see how can we modify it.
1 Here, we are creating two functions `incCount` and `decCount` which will be used to increment and decrement the count property respectively.
2.Then we make two buttons labeled `Add` and `Dec`.They will have onClick event handler which will trigger `incCount` and `decCount` methods on button clicks.
If you click on any of these two buttons you will see that the component state doesn’t change(i.e the number doesn’t change). So to make the component re-render when the mobx state is changed, we would need to make every component as observers. After doing that Mobx will make sure your state and Component remain in Sync all the time.
That can be by simply importing observer from a mobx-react package and wrapping it to a counter component.
Now we will be able to see changes in UI whenever there is any change in mobx state.
Actions are functions that modify the state. Regular functions can also modify the state but actions yield better performance and It informs computed property whenever action is completed. We will cover computed property later in detail. So it is a good practice to modify states in actions instead of regular functions.
Before learning more about actions, we are going to apply a configuration which allows only actions to modify states. You can think of it like mobx in strict mode.
Now we are importing `configure` from the mobx package and applying `enforceActions` as true. Now if we try to modify the state without action, components won’t re-render.
Thus, if you try to click on Add or Dec buttons we will get below warning!
You will see above error message which says that regular function cannot modify state and only actions can. So let us now convert the function into actions.
It can be done by importing `action` from a mobx package and wrap it in a given function. Now if you click on Add/Dec button you will see that the state changes.
Now let us install `mobx-dev-tools`, which gives us the ability to detect changes in mobx state.
We can simply install it by running command
yarn add mobx-react-devtools — dev
Now that we have imported Devtools from mobx-react-devtools package and we are ready to add it anywhere in Counter component.
If you head over to the browser you will see three icons on the right. If we click on the last icon, it becomes highlighted. If we will click on Add or Dec button, the console will show us which actions
got triggered and how values get updated and which components re-rendered because of the state change.
As you can see in above snippet, `action` is showing as `unnamed action`. If you have a lot of action it becomes difficult to debug so to solve this problem we can name our action in such a way which will allow us to debug better.
Above you can see, I have `named action` by passing string in the first parameter.
In a console, you will see action name instead of `unnamed action` like in a previous snippet.
Computed Property is recommended as a way of accessing data from Mobx State. If you want to access data as it was stored in Mobx State then you don’t need a Computed property, but if you want to do some modification on data before accessing it, then using Computed Property is the best way of doing it.
Here we see two numbers, one is count multiplied by 3 and another is count multiplied by 4.
Let see, if can we use count property as it was stored in Mobx State without any modification?
No, because we don’t have data stored in multiple of 3 or 4 in Mobx state, so in this scenario, it would be better to use computed property.
As you can see it is not possible to use count property directly from the Mobx state without doing any modification, as we need to the count in multiples of 3 and 4 so we would be using a computed property to access count by updating its value.
I above example we see how can a computed property is created and also how we can use `this` which points to appState in computed property. you can see I am accessing count property by multiplying it by 3 or 4 and then returning it. [We are accessing count property by multiplying it by 3 and 4 and then returning it.]
Now let’s see how can we use it in our Component.
In above snippet, we are using computed properties `countByThree` and `countByFour` in `Counter` component. Since it a computed property, you do not need to call it as a function, instead, call just with its name like we access any other property. Also, note that they cannot accept any parameters as they are not normal functions.
If you click on `Add` Button you will see that incremented number gets multiplied by 3 and 4. In the same way, if you decrement the number it decrements and gets multiplied by 3 and 4. So Computed Property only reacts/ re-runs, if its dependent state is changed. Here computed properties depend on `count` count so if the count is updated computed property will re-run otherwise, it is suspended which gives us performance boosts in our application.