Reacting to Observables with MobX-React
By: John Au-Yeung
Tags: JavaScript, Programming, Web Development, Technology, React

Photo by Jens Johnsson on Unsplash

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.

Photo by Max Rovensky on Unsplash

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 or shouldComponentUpdate 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.

A note from JavaScript In Plain English:

We are always interested in helping to promote quality content. If you have an article that you would like to submit to JavaScript In Plain English, send us an email at submissions@javascriptinplainenglish.com with your Medium username and we will get you added as a writer.

We have also launched three new publications! Show some love for our new publications by following them: AI in Plain English, UX in Plain English, Python in Plain English — thank you and keep learning!