Site icon Coding is Love

How to setup Mobx with react context

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 in 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 :

https://codingislove.com/wp-content/uploads/2020/06/mobx-react-context-demo.mp4

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 ✌️

Exit mobile version