MobX

Language: JavaScript

State Management

MobX was created by Michel Weststrate to provide a reactive state management solution that is less verbose and more intuitive than Redux. It leverages observables and derivations to automatically update UI components when state changes, reducing boilerplate and promoting a reactive programming paradigm.

MobX is a simple, scalable, and battle-tested state management library for JavaScript applications. It allows you to manage application state outside of components while keeping your UI automatically in sync with state changes.

Installation

npm: npm install mobx mobx-react
yarn: yarn add mobx mobx-react

Usage

MobX uses observables to hold state, actions to modify state, and reactions or observers to automatically update the UI. Computed values allow derived state to be calculated efficiently. MobX integrates seamlessly with React via the `observer` higher-order component or hooks.

Creating an observable store

import { makeAutoObservable } from 'mobx';

class CounterStore {
  count = 0;
  constructor() {
    makeAutoObservable(this);
  }
  increment() {
    this.count += 1;
  }
  decrement() {
    this.count -= 1;
  }
}

const counterStore = new CounterStore();
export default counterStore;

Defines a store with observable state and actions. `makeAutoObservable` automatically makes state observable and actions reactive.

Using MobX store in a React component

import { observer } from 'mobx-react';
import counterStore from './CounterStore';

const Counter = observer(() => (
  <div>
    <button onClick={() => counterStore.decrement()}>-</button>
    <span>{counterStore.count}</span>
    <button onClick={() => counterStore.increment()}>+</button>
  </div>
));

Wraps the component with `observer` so it re-renders automatically when `counterStore.count` changes.

Computed values

import { makeAutoObservable } from 'mobx';

class CartStore {
  items = [];
  constructor() { makeAutoObservable(this); }
  addItem(item) { this.items.push(item); }
  get total() { return this.items.reduce((sum, item) => sum + item.price, 0); }
}

const cartStore = new CartStore();

Defines a computed value `total` that automatically recalculates when `items` change.

Reaction example

import { reaction } from 'mobx';
reaction(() => cartStore.total, total => {
  console.log('Cart total changed to:', total);
});

Sets up a reaction that triggers a callback whenever `cartStore.total` changes.

Asynchronous actions

import { makeAutoObservable, runInAction } from 'mobx';

class AsyncStore {
  data = [];
  loading = false;
  constructor() { makeAutoObservable(this); }
  async fetchData() {
    this.loading = true;
    const response = await fetch('/api/data');
    const result = await response.json();
    runInAction(() => {
      this.data = result;
      this.loading = false;
    });
  }
}

Demonstrates performing asynchronous operations safely with MobX using `runInAction`.

Error Handling

UI not updating: Ensure components using observables are wrapped with `observer` or use `useObserver` hook.
State mutation outside action: Enable `enforceActions` and make all state modifications inside actions.
Computed values not recalculating: Make sure computed properties access observable state and are not dependent on non-observable values.

Best Practices

Use small, focused stores to manage state for different parts of the app.

Wrap React components with `observer` to automatically update UI when observables change.

Use `computed` for derived state to optimize performance.

Avoid directly mutating observables outside of actions for predictable behavior.

Leverage MobX DevTools for debugging and inspecting state changes.