mobx vs redux vs vuex
フロントエンド状態管理ライブラリの選定基準
mobxreduxvuex類似パッケージ:

フロントエンド状態管理ライブラリの選定基準

redux、mobx、vuex は、アプリケーション全体のデータを管理するためのライブラリです。redux は予測可能な状態変化を重視し、アクションとレデューサーを通じてデータを変更します。mobx は観測可能な状態を使い、変更を自動的に検知して更新します。vuex は Vue.js 専用の公式状態管理で、中央集権的なストアを提供します。これらはそれぞれ異なる考え方に基づいており、プロジェクトの規模やチームの嗜好に合わせて選ぶ必要があります。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
mobx028,2194.89 MB193日前MIT
redux061,441290 kB173年前MIT
vuex028,289271 kB144-MIT

Redux vs MobX vs Vuex: 状態管理アーキテクチャの比較

redux、mobx、vuex はいずれもアプリケーションの状態を管理するためのツールですが、その仕組みと使い勝手は大きく異なります。実務で直面する課題に対して、それぞれがどうアプローチするかを比較します。

🔄 状態の更新方法:直接変更 vs 间接更新

redux は状態を直接変更できません。アクションを dispatch し、レデューサーが新しい状態を返します。

  • 状態は不変(immutable)として扱われます。
  • 変更履歴を追跡しやすい構造です。
// redux: Action dispatch
store.dispatch({ type: 'INCREMENT' });

// reducer
function counter(state = 0, action) {
  if (action.type === 'INCREMENT') return state + 1;
  return state;
}

mobx は状態を直接変更できます。観測可能なプロパティを書き換えると、自動で反応します。

  • 状態は可変(mutable)です。
  • 書き方が自然で、コード量が少なくなります。
// mobx: Direct mutation
import { makeObservable, action, observable } from "mobx";

class Store {
  count = 0;
  constructor() {
    makeObservable(this, { count: observable, increment: action });
  }
  increment() {
    this.count++;
  }
}
const store = new Store();
store.increment();

vuex はミューテーションを通じて状態を変更します。

  • 直接変更は禁止されており、コミットを経由します。
  • 変更箇所を明確に記録できます。
// vuex: Commit mutation
store.commit('INCREMENT');

const store = createStore({
  state: () => ({ count: 0 }),
  mutations: {
    INCREMENT(state) {
      state.count++;
    }
  }
});

📝 必要なコード量:定型文 vs 簡潔さ

redux は構造を守るために多くのコードが必要です。

  • アクションタイプ、アクションクリエイター、レデューサーを定義します。
  • 近年は Redux Toolkit を使うことで大幅に削減できます。
// redux (Traditional)
const ADD_TODO = 'ADD_TODO';
function addTodo(text) { return { type: ADD_TODO, text }; }
function todos(state = [], action) { /* ... */ }

mobx はクラスとデコレータ(または makeObservable)だけで済みます。

  • 余計な設定ファイルは不要です。
  • 状態とロジックを同じ場所にまとめられます。
// mobx
class TodoStore {
  todos = [];
  addTodo(text) {
    this.todos.push({ text });
  }
}

vuex はストアの定義に一定の構造を要求します。

  • state、mutations、actions、getters を分けて書きます。
  • 単一ファイルコンポーネント内にまとめることも可能です。
// vuex
export default createStore({
  state: { todos: [] },
  mutations: { add(state, text) { /*...*/ } },
  actions: { addTodo({ commit }, text) { commit('add', text); } }
});

🧩 フレームワークとの連携:汎用 vs 専用

redux はフレームワークを選びません。

  • React、Vue、Angular などで使えます。
  • React との相性が特に良く、エコシステムが充実しています。
// redux + React
import { useSelector } from 'react-redux';
function Counter() {
  const count = useSelector(state => state.count);
  return <div>{count}</div>;
}

mobx もフレームワークを選ばない汎用ライブラリです。

  • React、Vue、Svelte などで利用可能です。
  • 各フレームワーク用のバインディングパッケージがあります。
// mobx + React
import { observer } from 'mobx-react-lite';
const Counter = observer(() => {
  return <div>{store.count}</div>;
});

vuex は Vue.js 専用です。

  • Vue 2 および Vue 3 と強く統合されています。
  • 他のフレームワークでは使用できません。
// vuex + Vue
import { useStore } from 'vuex';
export default {
  setup() {
    const store = useStore();
    return { count: computed(() => store.state.count) };
  }
};

⚠️ 現在の維持状況と推奨事項

redux は現在も活発に開発されています。

  • 素の redux パッケージよりも Redux Toolkit の使用が公式に推奨されています。
  • 長期的なサポートが期待できます。
// Redux Toolkit (Modern Standard)
import { createSlice } from '@reduxjs/toolkit';
const slice = createSlice({ name: 'counter', initialState: 0, reducers: { increment: state => state + 1 } });

mobx も安定して維持されています。

  • バージョン 6 以降はクラスベースの設計が主流です。
  • 特定のフレームワークに依存しないため、継続利用に安心感があります。
// mobx v6+
import { makeAutoObservable } from "mobx";
class Store {
  constructor() { makeAutoObservable(this); }
}

vuex は Vue 3 において維持モードに入っています。

  • 新規プロジェクトでは pinia の使用が公式に推奨されています。
  • Vue 2 のレガシープロジェクト以外での採用は避けるべきです。
// Pinia (Recommended for Vue 3)
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }) });

🤝 共通点:状態管理ライブラリの役割

これら 3 つのライブラリは、異なるアプローチを取りながらも、共通の目的を持っています。

1. 🌍 グローバルな状態共有

  • コンポーネント間のプロパティドリルを解消します。
  • 任意の場所から状態にアクセスできます。
// 全て共通:グローバルストアへのアクセス
const state = store.state; // vuex
const state = store.getState(); // redux
const state = store.count; // mobx

2. 🔍 開発者ツールの対応

  • 状態の変化をデバッグツールで可視化できます。
  • 時間旅行デバッグ(redux)や反応の追跡(mobx)が可能です。
// 全て共通:DevTools 連携
// redux: Redux DevTools Extension
// mobx: MobX Developer Tools
// vuex: Vue Devtools

3. 🧪 予測可能性の向上

  • 状態変更のルールを定めることで、バグを減らします。
  • テストしやすい構造を提供します。
// 全て共通:テスト可能なロジック
// redux: reducer testing
// mobx: action testing
// vuex: mutation testing

📊 比較サマリー

特徴reduxmobxvuex
状態変更间接(アクション)直接(代入)间接(ミューテーション)
学習コスト高い(概念が多い)低い(直感的)中程度(Vue 依存)
コード量多い(Toolkit で削減可)少ない中程度
フレームワーク汎用(React 中心)汎用Vue 専用
現状活発(Toolkit 推奨)安定維持モード(Pinia 推奨)

💡 最終的な推奨

redux は、大規模で複雑な状態管理が必要な場合に最適です。特に React エコシステムでは事実上の標準であり、チーム規模が大きくなっても構造を維持できます。ただし、設定の手間を減らすために Redux Toolkit の使用を強く推奨します。

mobx は、開発速度とコードの簡潔さを優先する場合に適しています。状態変更の追跡が緩やかでも問題ないプロジェクトや、クラスベースの設計を好むチームに向いています。フレームワークを選ばない柔軟性も魅力です。

vuex は、Vue 2 の既存プロジェクトを維持する場合のみ選択してください。Vue 3 で新規開発を行う場合は、より簡潔で型サポートも強い pinia への移行を検討すべきです。状態管理ライブラリとしての役割は終わりに近づいています。

結論: 新規プロジェクトでは、React なら redux (Toolkit)、Vue なら pinia、フレームワークに縛られない柔軟性が必要なら mobx を選ぶのが賢明です。

選び方: mobx vs redux vs vuex

  • mobx:

    少コードで状態管理を実装したい場合に適しています。クラスベースの設計やオブジェクト指向的な書き方を好むチームに向いています。魔法のような自動更新機能を使っても問題ない場合、開発速度を優先できます。ただし、状態変更の追跡が緩くなるため、大規模化すると挙動を把握しづらくなる可能性があります。

  • redux:

    大規模なプロジェクトで、状態変化の履歴を追跡したい場合に最適です。データフローが明確になるため、チームでの共同開発やバグ調査がしやすくなります。標準的な書き方が確立されており、採用事例も豊富です。ただし、定型文が多いため、小規模なアプリではオーバースペックになることがあります。

  • vuex:

    Vue 2 を使用している既存プロジェクトでは依然として有効です。しかし、Vue 3 で新規開発する場合は、公式に推奨されている pinia の検討を強くお勧めします。vuex は維持モードに入っており、新しい機能追加は期待できません。Vue エコシステムに深く統合された状態管理が必要な場合のみ選定します。

mobx のREADME

logo

MobX

Simple, scalable state management.

npm version OpenCollective OpenCollective Discuss on Github Coverage Status View changelog


Documentation

Documentation can be found at mobx.js.org.


Sponsors

MobX is made possible by the generosity of the sponsors below, and many other individual backers. Sponsoring directly impacts the longevity of this project.

🥇🥇 Platinum sponsors ($5000+ total contribution): 🥇🥇


Guilded Canva Parallax

🥇 Gold sponsors ($2500+ total contribution):


One Beyond Frontend Masters Auction Frontier CodeFirst Modulz Coinbase Curology Mendix Facebook Open Source Casino Sites Bugsnag

🥈 Silver sponsors ($500+ total contributions):

mantro GmbH Extremely Heavy Industries Algolia Space307 Blokt UPPER DAZN talentplot EaseUS Route Planner and Route Optimizer Handsontable

Introduction

Anything that can be derived from the application state, should be. Automatically.

MobX is a signal based, battle-tested library that makes state management simple and scalable by transparently applying functional reactive programming. The philosophy behind MobX is simple:

😙

Straightforward

Write minimalistic, boilerplate-free code that captures your intent. Trying to update a record field? Simply use a normal JavaScript assignment — the reactivity system will detect all your changes and propagate them out to where they are being used. No special tools are required when updating data in an asynchronous process.

🚅

Effortless optimal rendering

All changes to and uses of your data are tracked at runtime, building a dependency tree that captures all relations between state and output. This guarantees that computations that depend on your state, like React components, run only when strictly needed. There is no need to manually optimize components with error-prone and sub-optimal techniques like memoization and selectors.

🤹🏻‍♂️

Architectural freedom

MobX is unopinionated and allows you to manage your application state outside of any UI framework. This makes your code decoupled, portable, and above all, easily testable.


A quick example

So what does code that uses MobX look like?

import React from "react"
import ReactDOM from "react-dom"
import { makeAutoObservable } from "mobx"
import { observer } from "mobx-react-lite"

// Model the application state.
const myTimer = makeAutoObservable({
    secondsPassed: 0,
    increase() {
        this.secondsPassed += 1
    },
    reset() {
        this.secondsPassed = 0
    }
})

// Build a "user interface" that uses the observable state.
const TimerView = observer(({ timer }) => (
    <button onClick={() => timer.reset()}>Seconds passed: {timer.secondsPassed}</button>
))

ReactDOM.render(<TimerView timer={myTimer} />, document.body)

// Update the 'Seconds passed: X' text every second.
setInterval(() => {
    myTimer.increase()
}, 1000)

The observer wrapper around the TimerView React component will automatically detect that rendering depends on the timer.secondsPassed observable, even though this relationship is not explicitly defined. The reactivity system will take care of re-rendering the component when precisely that field is updated in the future.

Every event (onClick / setInterval) invokes an action (myTimer.increase / myTimer.reset) that updates observable state (myTimer.secondsPassed). Changes in the observable state are propagated precisely to all computations and side effects (TimerView) that depend on the changes being made.

MobX unidirectional flow

This conceptual picture can be applied to the above example, or any other application using MobX.

Getting started

To learn about the core concepts of MobX using a larger example, check out The gist of MobX page, or take the 10 minute interactive introduction to MobX and React. The philosophy and benefits of the mental model provided by MobX are also described in great detail in the blog posts UI as an afterthought and How to decouple state and UI (a.k.a. you don’t need componentWillMount).

Further resources

The MobX book

The MobX Quick Start Guide ($24.99) by Pavan Podila and Michel Weststrate is available as an ebook, paperback, and on the O'Reilly platform (see preview).

Videos

Credits

MobX is inspired by reactive programming principles, which are for example used in spreadsheets. It is inspired by model–view–viewmodel frameworks like MeteorJS's Tracker, Knockout and Vue.js, but MobX brings transparent functional reactive programming (TFRP, a concept which is further explained in the MobX book) to the next level and provides a standalone implementation. It implements TFRP in a glitch-free, synchronous, predictable and efficient manner.

A ton of credit goes to Mendix, for providing the flexibility and support to maintain MobX and the chance to prove the philosophy of MobX in a real, complex, performance critical applications.