Mobx is a Javascript library for state management. It is not specific to react but works great with react. Let’s see how to setup Mobx with react and react context specifically.
What is react context?
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
In simple words, React context is used to store some data at one place and use it all over the app. Components also re-render every time the data in context is modified. If we don’t use context then we would be passing data manually using props.
Technically, Mobx and other state management libraries also do the same thing but with more features
Why use Mobx with react context?
It is not mandatory to use react context with Mobx but it is recommended now officially on the mobx-react website.
Earlier, Mobx had an Provider/inject
pattern. There’s one Provider
in the root, inject
is used to inject the mobx store to any component and observer
is used to make a component re-render whenever the store is modified.
This Provider/inject
works great but it is heavily opinionated. Provider/inject
pattern still works with mobx-react 6.x but it is considered as obsolete now. You can read more about it here – Why inject pattern is obsolete
So, It is better to use Mobx with react context starting from mobx-react 6.x but the problem is the official docs on setting up Mobx with react context is quite confusing.
If you read the docs then there will be many questions in your mind. Like how to use Mobx react context with class components , how to use Mobx react context with functional components, how to observe for changes on class components and functional components.
Official docs only mention how to use context and mobx with hooks but there’s nothing related to class components. I’m pretty sure that majority of the react developers are still using class components even if they have started using hooks.
So I’m writing this detailed guide on how to setup Mobx with react context to clarify any such questions.
How to setup Mobx with react native
This exact setup works with react native as well. Just skip the react specific sections. I’m assuming that you have a basic react native app generated using react-native-cli. Everything else remains the same.
Basic react app
I’m starting from scratch just to be clear but if you already have a react app setup then that is completely fine and you can skip this section.
Create a basic react app using create-react-app
by running the following command :
npx create-react-app my-app
You have a basic app now. You can cd
into the newly created app and run it using.
cd my-app && yarn start
If you go to http://localhost:3000/
then you can see a basic react app running which looks like this :
We need to eject from create-react-app for enabling Mobx decorators syntax. Eject using :
yarn eject
Install Mobx and Mobx-react
Mobx is the main library and mobx-react has the mobx binding for react. Install both Mobx and Mobx-react using the following command :
yarn add mobx mobx-react
If you had already setup react app and Mobx then Make sure that mobx-react is 6.x or higher
Enable Mobx decorators syntax
You can use Mobx without the decorators syntax as well but using decorators simplifies the code so let’s enable it.
Enable decorators for react app
Make sure that you have ejected from create-react-app as mentioned above using yarn eject
Install the babel plugins for decorators using :
yarn add --dev @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties
Go to package.json file and replace the babel section with the following
"babel": {
"presets": [
"react-app"
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": true }]
]
}
Enable decorators for react-native
Install the babel plugins for decorators using :
yarn add --dev @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties
Go to babel.config.js
and paste this :
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { loose: true }],
],
};
Decorator syntax is enabled now!
Setup a basic Mobx store
go to src folder in react app, create a folder named services
and create a file named store.js
inside the services folder. You create this file anywhere in the project as per your preference. I’m just showing an example to organize it properly.
Go to newly created store.js
file and paste the following code
import React from "react";
import { action, observable } from "mobx";
/* Store start */
export default class Store {
@observable title = "Coding is Love";
@observable user = {
userId: 1,
name: "Ranjith kumar V",
website: "https://codingislove.com",
email: "ranjith@codingislove.com",
};
@action
setUser(user) {
this.user = user;
}
@action
updateUser(data) {
this.user = { ...this.user, ...data };
}
@action
clearUser() {
this.user = undefined;
}
@action
setTitle(title) {
this.title = title;
}
}
/* Store end */
/* Store helpers */
const StoreContext = React.createContext();
export const StoreProvider = ({ children, store }) => {
return (
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
);
};
/* Hook to use store in any functional component */
export const useStore = () => React.useContext(StoreContext);
/* HOC to inject store to any functional or class component */
export const withStore = (Component) => (props) => {
return <Component {...props} store={useStore()} />;
};
Store explanation
Its a very simple store with a user object to store user data, a title string, a few functions to modify the user and title. @observable
is used to tell mobx to re-render components whenever an observable property is modified.
@action
is a function that is used for modifying observables. Running an @actions
also triggers autoRun
functions if you have set up any of them.
useStore is our custom hook to use mobx store in any functional component
withStore is a custom HOC (Higer order component) to use mobx store in any class component.
Mobx Provider setup
Go to your main file. App.js
in case of create-react-app and paste this :
import React from "react";
import Home from "./screens/Home";
import Store, { StoreProvider } from "./services/store";
const store = new Store();
/* Create a new store */
function App() {
return (
<StoreProvider store={store}>
<Home />
</StoreProvider>
);
}
export default App;
We are using StoreProvider
in the root and a single component named Home
Create a folder called screens
and create a file named Home.js
inside the folder and paste this :
import React, { Component } from "react";
import logo from "../logo.svg";
import "../App.css";
import { observer } from "mobx-react";
import { withStore } from "../services/store";
@withStore
@observer
class Home extends Component {
toggleTitle = () => {
const { store } = this.props;
if (store.title === "Coding is Love") {
store.setTitle("Mobx React Context");
} else {
store.setTitle("Coding is Love");
}
};
render() {
const { store } = this.props;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<a
className="App-link"
href="https://codingislove.com"
target="_blank"
rel="noopener noreferrer"
>
{store.title}
</a>
<button onClick={this.toggleTitle} style={{ margin: 20 }}>
Toggle title
</button>
</header>
</div>
);
}
}
export default Home;
We are using @withStore HOC that was created in store.js
to use our store. @observer is used to re-render the component whenever store is modified.
This is an example of How to use Mobx and react context setup with class components
withStore HOC injects store into the component as a prop so we can accessing it using this.props.store
I’ve written one small function named toggleTitle
just to show how to modify the store.
That’s it! We’ve completed the mobx setup! Now, Whenever we modify the store, all the components with observer get re-rendered automatically.
If you want to know how to use the useStore
hook then continue reading.
useStore hook for functional components
This is an example on How to use Mobx and react context with functional components. Create a folder named components
inside src folder. Create a file named Username.js
inside components
folder.
Go to Username.js
and paste this :
import React from "react";
import { observer } from "mobx-react";
import { useStore } from "../services/store";
const Username = observer(() => {
const store = useStore();
return <div style={{ fontSize: 14 }}>- By {store.user.name}</div>;
});
export default Username;
All we have to do is use observer so that the component re-renders when store is modified. Use the store using useStore
hook. It is as simple as that.
Now import the Username
in Home.js
and use it.
Final code looks like this:
import React, { Component } from "react";
import logo from "../logo.svg";
import "../App.css";
import Username from "../components/Username";
import { observer } from "mobx-react";
import { withStore } from "../services/store";
@withStore
@observer
class Home extends Component {
toggleTitle = () => {
const { store } = this.props;
if (store.title === "Coding is Love") {
store.setTitle("Mobx React Context");
} else {
store.setTitle("Coding is Love");
}
};
render() {
const { store } = this.props;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<a
className="App-link"
href="https://codingislove.com"
target="_blank"
rel="noopener noreferrer"
>
{store.title}
</a>
<button onClick={this.toggleTitle} style={{ margin: 20 }}>
Toggle title
</button>
<Username />
</header>
</div>
);
}
}
export default Home;
Wrapping up
Final output looks like this :
Full source code for this boilerplate project is available here – https://github.com/codingislove01/mobx-react-context
If you have any questions or feedback then let me know in the comments below
The post How to setup Mobx with react context appeared first on Coding is Love.