We can use MobX with MobX-React to manage the state by watching MobX observables and changing the observable data.
In this article, we’ll look at how to create an Observable and use it in React components directly.
Creating Observables and Using Them in React Components
We have to install the mobx
and mobx-react
packages to create Observables and use them within React components.
To do this, we can write the following:
npm i mobx mobx-react
Then we can create our Observable object and a React component that uses it as follows:
import React from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react";
import { observable } from "mobx";
const countData = observable({
count: 0
});
const App = observer(({ countData }) => (
<>
<button onClick={() => countData.count++}>Increment</button>
<p>{countData.count}</p>
</>
));
const rootElement = document.getElementById("root");
ReactDOM.render(<App countData={countData} />, rootElement);
In the code above, we created the countData
Observable object by writing:
const countData = observable({
count: 0
});
We’ll be able to get the latest state within our React component and then pass it in as a prop for our React component.
To make our React component watch for the latest value from our Observable object and let us change its value from within the component, we write:
const App = observer(({ countData }) => (
<>
<button onClick={() => countData.count++}>Increment</button>
<p>{countData.count}</p>
</>
));
const rootElement = document.getElementById("root");
ReactDOM.render(<App countData={countData} />, rootElement);
The code above gets the countData
prop from the countData
Observable. Then in the onClick
handler, we just pass in the function to change its value.
Then when we reference the App
component in the last line, we just pass in the countData
Observable object as the value of the countData
prop.
countData.count++
will change the state of the Observable, which then the latest value will be obtained from the prop.
We can use the countData
Observable object with class components as follows:
import React from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react";
import { observable } from "mobx";const countData = observable({
count: 0
});
@observer
class App extends React.Component {
render() {
return (
<>
<button onClick={() => countData.count++}>Increment</button>
<p>{countData.count}</p>
</>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App countData={countData} />, rootElement);
The only difference is that it’s a class component with a render method and that we use the observer
decorator instead of the observer
function.
Using Context to Pass Observables Around
We can use the React Context API to pass the values of an Observable to another component.
For instance, we can write the following code:
import React, { useContext } from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react";
import { observable } from "mobx";
const countData = observable({
count: 0
});
const CountContext = React.createContext();
const Counter = observer(() => {
const countData = useContext(CountContext);
return (
<>
<button onClick={() => countData.count++}>Increment</button>
<p>{countData.count}</p>
</>
);
});
const App = ({ countData }) => (
<CountContext.Provider value={countData}>
<Counter />
</CountContext.Provider>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<App countData={countData} />, rootElement);
In the code above, we have the CountContext
. We create it by writing:
const CountContext = React.createContext();
Then in App
, we included the CountContext
component, so that we can get the countData
Observable value by passing in the countData
prop with the value set to the countData
Observable.
In the Counter
component, we call the observer
function with a function component inside.
Inside the component, we use the useContext
hook to get the value from CountContext
.
Then in the handler function, we passed into the onClick
prop of the button, we changed the count
‘s value, which will automatically change the value in the countData
Observable object and set as the value of countData.count
.
Therefore, when we click the Increment button, the number below it will go up.
Storing Observables in Local Component State
We can also use Observables as a local state in a React component.
To do this, we can use the useState
hook by passing in a function that returns an Observable object as follows:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react";
import { observable } from "mobx";const App = observer(() => {
const \[countData\] = useState(() =>
observable({
count: 0
})
); return (
<>
<button onClick={() => countData.count++}>Increment</button>
<p>{countData.count}</p>
</>
);
});
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
In the code above, we used the useState
hook by passing in a function that returns an Observable object with the count
property. We then assigned that to the countData
variable.
Once we did that, countData.count
will be updated by the onClick
handler and when we click the Increment button, we’ll see the countData.count
value update automatically.
If we click the Increment button, then the value will go up.
We don’t really need to use MobX Observable objects to store local state unless complex computations are involved, since MobX will optimize for those.
Likewise, we can use MobX to store local state with class components as follows:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react";
import { observable } from "mobx";@observer
class App extends React.Component {
@observable count = 0; render() {
return (
<>
<button onClick={() => this.count++}>Increment</button>
<p>{this.count}</p>
</>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
In the code above, we have this.count
, which is an Observable field. In the onClick
listener, we just modify this.count
directly, and then it’ll be reflected in the this.count
in between the p
tag.
@observer
implements memo
orshouldComponentUpdate
automatically so that there won’t be any unnecessary re-renders.
Conclusion
We can use MobX Observable to store a React app’s state or a React component’s state.
To use it for storing React app’s state, we can either pass an Observable to a component as a prop or we can use the Context API to send the data to different components.
We can also use it to store local state by either using the useState
hook in function components and using the observable
decorator within a class component.