In this blog post, we will look at what is MobX, and how MobX can be used in React applications.
We will also look at a simple example using MobX and also build some complex examples using MobX.
What is MobX?
MobX is a state management library, it allows transparent state management and can be used when you require complex state management in your React applications.
It can be used with any framework and even in plain JavaScript applications to create an observable state, it is an un-opinioned framework that allows you to create decoupled code.
It offers helpers and higher-order observer
component to easily integrate with React and can be used as an alternative to redux.
Using Dead Simple Chat JavaScript Chat API and SDK you can add Chat to any React or Web application in minutes. It is a highly scaleable Chat Plaform.
Why use MobX with React?
Typically when you create React application you use the useState
hook provided by React.
And you should use the useState
hook unless your application grows very big and you require complex state management.
In that case, you could investigate some advanced state management tools that are scaleable, one of those tools is Mobx.
Basically, tools like MobX allow you to automatically update the UI automatically when the underlying state is updated.
To rephrase it, it handles automatic updation of the UI when the variables that affect are UI updated.
Key Mobx Concepts
The MobX has 3 core concepts:
- State
- Actions
- Derivations
1. The State:
The official MobX documents encapsulate it nicely, the "State is the data that drives your application."
The state stores any data that is required by your application, it can be a single variable, plain object or complex data structure.
To demonstrate the state we have created a class called as the CounterStore
. The CounterStore
acts as a very simple data store for our application.
In our CounterStore
the count
variable is our State.
In the constructor, we called a helper method from Mobx called makeAutoObservable(this)
and passed it this
so that it can keep track of the changes in our CounterStore
datastore.
2. Actions
Anything that modifies or updates the state are called as actions. The actions help you structure the code and prevent the inadvertently changing of the state.
Actions also help you keep track of the changes to the state. The state should never be updated directly, and actions should be created to update the state.
In our CounterStore
example the method increment()
and decrement()
are the Actions.
Because the methods increment()
and decrement()
are updating our state variable count
.
// store.js
import { makeAutoObservable } from 'mobx';
class CounterStore {
count = 0; // The State
constructor() {
makeAutoObservable(this);
}
increment() { // Action
this.count++;
}
decrement() { // Action
this.count--;
}
}
export const counterStore = new CounterStore();
3. Derivations
Anything that can be derived from the state is called a Derivation.
For e.g in our CounterStore
if we are using the count
state somewhere in our application, when the count
value is updated the UI displaying the count should also update.
MobX provides us with automatic derivations, with the help of the makeAutoObservable()
method that we have seen before and observer
Higher order component that we will see next.
// App.js
import React from "react";
import { observer } from "mobx-react-lite";
import { counterStore } from "./store";
const App = observer(() => {
return (
<div>
<h1>Counter App using React+MobX</h1>
<p>Count: {counterStore.count}</p>
<button
onClick={() => {
counterStore.increment();
}}
>
Increment
</button>
<button
onClick={() => {
counterStore.decrement();
}}
>
Decrement
</button>
</div>
);
});
export default App;
As you can see in the code sample above, as the state is update the UI is also updated automatically.
Here is the complete example running in CodeSandbox:
Advanced Example using MobX
We will now look at an advanced example using Mobx in this example we will create a Todo application that uses React Context Provider which is provided by MobX to inject state into the components.
If you want a tutorial on how React Context works you refer to our React Context Guide. (Even if you don't know how React Context works you can still follow the tutorial)
- We will scaffold a react application using
create-react-app
.
npx create-react-app react-mobx
cd react-mobx
2. Next we will install mobx
and mobx-react
packages to use MobX in our react application. We are also installing the uuid
package to generate a unique id for our Todos.
npm install --save mobx mobx-react uuid
3. Now we will create an Observable store to save our Todos, create a file named store.js
under the src/
folder.
Update your index.js
file to include the store and the Provider
from Mobx, and wrap the <Provider ..
around our <App />
component.
4. We will now create a CreateTodo.js
file to hold our CreateTodo
component. This component will allow us to add Todos.
We have created a CreateTodo
component, this component connects to our store using React's useContext()
hook.
Using the helper Provider
component offered by MobX, MobX creates the context for our TodoStore
.
Which we have used in our CreateTodo
component to interact with the store.
The rest of the code is very straightforward, there is a local state variable called as title
which we are updating each time the input text box is updated using the onChange
method.
When the form is submitted we are calling the handleSubmit
method, and setting the value of the title
variable as a todo and clearing it.
5. Next, we will create a TodoItem.js
file, this will hold our TodoItem component, the TodoItem component will show a single todo on the screen, and would also allow the user to toggle the todo.
In our code example above, we are importing the store using the useContext
and calling the toggleCompleted()
method when the todo is checked and removeTodo
method to delete to Todo.
6. Finally we will update our App.js
file to display the list of the Todos, and import our <CreateTodo />
component.
We will fetch all the Todos from the store and iterate over them and will add TodoItem
component to display the Todo.
As you can see in the live code sandbox below, when the item in the store is Added, Updated to Delete the UI automatically updates.
We are using 3 components, App, CreateTodo and TodoItem and all the components are accurately reflecting the state information and are getting updated each time the Todo updates.
Another Example of using MobX: Fetching data via HTTP
In this example, we will create a PostStore
that stores a list of posts. The List of Posts is retrieved from an API.
We will use the jsonplaceholder.typicode.com/posts
API to fetch a mock list of Posts and save them in our store.
In the store, we will create a method to fetch the posts, which can be called from the component using the store.
- Under the
src/
folder create a file namedstore.js
this will contain our PostStore and our PostStoreContext.
// src/store.js
import { makeAutoObservable } from "mobx";
import { createContext } from "react";
class PostStore {
posts = [];
loading = false;
constructor() {
makeAutoObservable(this);
}
async fetchPosts() {
this.loading = true;
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts"
);
const data = await response.json();
this.posts = data;
} catch (error) {
console.error("Error fetching posts:", error);
} finally {
this.loading = false;
}
}
}
export const postStore = new PostStore();
export const PostStoreContext = createContext(postStore);
In the above code, we have created a fetchPosts()
method to fetch a list of users, and we are saving them in posts
variable.
2. Now let's update index.js
file and wrap our <App />
component in a provider, this will allow us to call useContext
inside the child components to access our store.
// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { PostStoreContext, postStore } from "./store";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<PostStoreContext.Provider value={postStore}>
<App />
</PostStoreContext.Provider>
</React.StrictMode>,
document.getElementById("root")
);
3. Next we will create a PostList component that will display a list of posts, create a file named PostList.js
that will hold our PostLists
component
// src/PostList.js
import { useContext } from "react";
import { observer } from "mobx-react-lite";
import { PostStoreContext } from "./store";
const PostList = observer(() => {
const store = useContext(PostStoreContext);
if (store.loading) {
return <div>Loading posts...</div>;
}
return (
<ul>
{store.posts.map((post) => (
<li key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</li>
))}
</ul>
);
});
export default PostList;
Here in the PostList
component we are calling useContext
on the PostStoreContext
to fetch the list of posts from the store and displaying them in a list.
4. Finally we will update our <App />
component. In the App component as will use the PostStoreContext
and create a button to call the fetchPosts()
method.
Calling the fetchPosts()
method will trigger and API call, and as the response is received from the API, the UI will be automatically updated with a list of new posts.
// src/App.js
import React, { useContext } from "react";
import { observer } from "mobx-react-lite";
import PostList from "./PostList";
import { PostStoreContext } from "./store";
const App = observer(() => {
const store = useContext(PostStoreContext);
const handleFetchPosts = () => {
store.fetchPosts();
};
return (
<div>
<h1>Posts powered by Mobx</h1>
<button onClick={handleFetchPosts}>Fetch Posts</button>
<PostList />
</div>
);
});
export default App;
You can try out the complete code in the codesanbox below:
JavaScript Chat API and SDK from Dead Simple Chat allows you to add Chat to your React Application is minutes. The Dead Simple Chat is very verstaile chat plaform that can be customised for any use-case.
You might be interested in some of our other articles
- React State Management: A Guide 2023
- React useReducer and Reducer: Guide with Examples
- React Context: The Detailed Guide
- React useState: The Complete guide
Key Takeaways
- MobX is a state management library. It can be used with any framework but offers helper methods to use with React using
react-mobx
package. - MobX should be used when complex state management is required if you want to avoid prop drilling and in cases where you require a global shared state among multiple components.
- You should first try using
useState
and passing data using props, or using Higher Order Components if it gets too cumbersome then only you should use a state management library like MobX. - MobX allows the management of the complicated state, but its use in the application should be carefully planned, otherwise, it might result in tightly coupled components.
- In this guide, we have learned what MobX is and looked at some basic as well as complex examples using MobX.