Mobx is a simpler alternative to state management for React apps. It works by creating a store and then watching it for changes, and we update the store by changing the values directly.
In this article, we’ll look at how to use Mobx and React together.
Installation
We install the mobx
and mobx-react
libraries to create our Mobx store and then connect it to our React component.
To do this, we run:
npm install mobx mobx-react
All modern browsers are supported by Mobx with version 4.x or earlier. Since version 5, Mobx uses proxies for state updates so Internet Explorer isn’t supported. It also works with React Native and Node.js
Basic Usage
To start using it, we create a store to hold the state. Then we can pass the store into our component.
For example, we can use Mobx to create a store then inject the store into our React component as follows:
import React from "react";
import ReactDOM from "react-dom";
import { observable } from "mobx";
import { observer } from "mobx-react";
class Count {
@observable count = 0;
}
const App = observer(({ store }) => {
return (
<div className="App">
<button
onClick={() => {
store.count++;
}}
>
Increment
</button>
<button
onClick={() => {
store.count--;
}}
>
Decrement
</button>
<p>{store.count}</p>
</div>
);
});
const store = new Count();
const rootElement = document.getElementById("root");
ReactDOM.render(<App store={store} />, rootElement);
In the code above, we created a store by defining the Count
class:
class Count {
@observable count = 0;
}
Then we create a new instance of the Count
class so that we can pass it into our component as a prop by writing:
const store = new Count();
and:
ReactDOM.render(<App store={store} />, rootElement);
Then to define our App
function component, we wrap a function around the observer
function so that the latest values from the store will be observed.
This means that once we pass in the store
, we’ll get the latest values automatically, and when we change the store properties that have the @observable
decorator before it, the value will be propagated to the store.
Therefore, in our onClick
props, we can pass in a function that changes store.count
directly to update the values, which then will immediately be reflected in store.count
that we added in the p
element.
We can also use the observer
decorator with React class component as follows:
import React from "react";
import ReactDOM from "react-dom";
import { observable, computed, autorun } from "mobx";
import { observer } from "mobx-react";
class Person {
@observable firstName = "Jane";
@observable lastName = "Smith";
@computed
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
@observer
class App extends React.Component {
render() {
const { store } = this.props;
return (
<div className="App">
<p>{store.fullName}</p>
</div>
);
}
}
const store = new Person();
const rootElement = document.getElementById("root");
ReactDOM.render(<App store={store} />, rootElement);
It does the same thing as the observer
function with React function components.
Computed Values and Getters
We can create a function in our store class that returns a value that’s computed from other observable values.
To do this, we can use the @computed
decorator before our method. We can define one and use it as follows:
import React from "react";
import ReactDOM from "react-dom";
import { observable, computed } from "mobx";
import { observer } from "mobx-react";
class Person {
@observable firstName = "Jane";
@observable lastName = "Smith";
@computed
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
const App = observer(({ store }) => {
return (
<div className="App">
<p>{store.fullName}</p>
</div>
);
});
const store = new Person();
const rootElement = document.getElementById("root");
ReactDOM.render(<App store={store} />, rootElement);
In the code above, we have a method fullName
in the Person
class that is a getter and it returns `${this.firstName} ${this.lastName}`
, which are the 2 observable properties we defined combined.
Then we can get the fullname
property in the store
prop as we did in the App
component.
Custom Reactions
Custom reactions are created by using the autorun
, reaction
, or when
functions by passing in a callback to them. Reactions are used for committing side effects.
For example, we can create them as follows:
autorun(() => {
console.log(store.fullName);
});
In the code above, we created a reaction that runs automatically when we run the code.
We log the value of store.fullName
from above, and we can use that in our component as follows:
const App = observer(({ store }) => {
autorun(() => {
console.log(store.fullName);
});
return (
<div className="App">
<p>{store.fullName}</p>
</div>
);
});
Conclusion
We can use Mobx to create a simple store to store our values. It comes with decorators and functions to get us to watch the values from React components and manipulate the store values directly.
With the observable
decorator, we can watch the values from the store and then save change the values directly.
The computed
decorator lets us get the functions from getters in the store class in our components.
To commit side effects, we can add custom reactions.