0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Redux・Zustand・Jotai状態管理ライブラリを比較してみる

0
Last updated at Posted at 2026-07-31

Redux・Zustand・Jotaiの違い

Reactの状態管理ライブラリには、Redux、Zustand、Jotaiなどがあります。

どれも複数のコンポーネントで状態を共有するために利用できますが、状態をどのような単位で管理し、どのようなルールで更新するかが異なります。

今回はReduxを基準として、それぞれの違いを整理します。


Reduxは状態の更新ルールを明確にする

Reduxでは、アプリケーションの状態をStoreに集約し、Actionをdispatchすることで状態を更新します。

Component
    ↓
dispatch(Action)
    ↓
Reducer
    ↓
Store
    ↓
Component

Reduxでは、画面から直接Stateを書き換えるのではなく、

  1. 何が起きたのかをActionで表す
  2. ReducerがActionを受け取る
  3. Reducerが新しいStateを作る

という流れで状態を更新します。

現在のReduxでは、Redux Toolkitを利用する方法が公式に推奨されています。Redux ToolkitのcreateSliceを使うことで、Reducer、Action Type、Action Creatorをまとめて定義できます。

import { createSlice, PayloadAction } from '@reduxjs/toolkit'

type CounterState = {
  count: number
}

const initialState: CounterState = {
  count: 0,
}

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.count += 1
    },
    add: (state, action: PayloadAction<number>) => {
      state.count += action.payload
    },
  },
})

export const { increment, add } = counterSlice.actions
export default counterSlice.reducer

コンポーネントからは、Actionをdispatchします。

const count = useSelector((state: RootState) => state.counter.count)
const dispatch = useDispatch()

<button onClick={() => dispatch(increment())}>
  増やす
</button>

Reduxの特徴は、単に状態を共有できることではありません。

状態がどのようなイベントによって、どのように変化したのかを明確にできることが大きな特徴です。

Redux DevToolsでは、dispatchされたActionと、それによって変化したStateを追跡できます。状態更新の経緯を確認しやすいため、複雑な業務ロジックや多人数での開発に向いています。


ZustandはReduxの構造をシンプルにした考え方

ZustandとReduxは、どちらも基本的にイミュータブルな状態モデルを採用しています。

一方で、ReduxがActionやReducerを通して状態を更新するのに対して、ZustandではStoreに定義した関数から直接状態を更新します。Zustand公式の比較ページでも、ReduxとZustandは概念的に似ていますが、Zustandでは通常ReactのProviderが不要である点が違いとして挙げられています。

Component
    ↓
StoreのAction
    ↓
set
    ↓
Store
import { create } from 'zustand'

type CounterStore = {
  count: number
  increment: () => void
  add: (value: number) => void
}

export const useCounterStore = create<CounterStore>()((set) => ({
  count: 0,

  increment: () =>
    set((state) => ({
      count: state.count + 1,
    })),

  add: (value) =>
    set((state) => ({
      count: state.count + value,
    })),
}))

コンポーネントからは、Storeに定義した関数を直接呼び出します。

const count = useCounterStore((state) => state.count)
const increment = useCounterStore((state) => state.increment)

<button onClick={increment}>
  増やす
</button>

Reduxでは、

dispatch(increment())

とActionをdispatchします。

Zustandでは、

increment()

とStoreの関数を直接実行します。

つまりZustandは、Reduxにある次のような仕組みを簡略化した設計と考えられます。

Redux
Component
  ↓
dispatch
  ↓
Action
  ↓
Reducer
  ↓
State更新
Zustand
Component
  ↓
Storeの関数
  ↓
State更新

コード量が少なく、状態と更新処理を近い場所に定義できるため、小規模から中規模のアプリケーションでは導入しやすい構成です。

その一方で、Reduxほど強いルールがないため、Storeの分割方法やActionの命名ルールをチームで決めておかないと、Storeが肥大化しやすくなります。


ReduxとZustandはSelectorの考え方が近い

ReduxとZustandでは、コンポーネントが必要なStateだけをSelectorで取得します。

Reduxの場合は、useSelectorを使用します。

const count = useSelector(
  (state: RootState) => state.counter.count,
)

Zustandでは、Store HookにSelectorを渡します。

const count = useCounterStore(
  (state) => state.count,
)

Zustand公式の比較ページでは、ReduxとZustandのレンダリング最適化の考え方に大きな違いはなく、どちらもSelectorによって必要な状態を選択する方法が推奨されています。

Store全体を取得するのではなく、コンポーネントが利用する値だけを選択する点は共通しています。

Redux
Store
 └── Selector
      └── 必要なStateを取得

Zustand
Store
 └── Selector
      └── 必要なStateを取得

そのため、Reduxを理解している場合、ZustandのSelectorも比較的理解しやすいでしょう。


JotaiはStoreではなくAtomを組み合わせる

JotaiはReduxやZustandとは異なり、状態をAtomという小さな単位で管理します。

import { atom } from 'jotai'

export const countAtom = atom(0)

コンポーネントでは、useAtomなどを使ってAtomを読み書きします。

import { useAtom } from 'jotai'
import { countAtom } from './countAtom'

const [count, setCount] = useAtom(countAtom)

<button onClick={() => setCount((value) => value + 1)}>
  増やす
</button>

Zustand公式の比較ページでは、ZustandとJotaiの大きな違いを次のように説明しています。

Zustand
→ 単一のStoreを作る

Jotai
→ 小さなAtomを組み合わせる

JotaiはAtom同士を組み合わせて、別の状態を作ることもできます。Atomの依存関係に基づいて、必要なコンポーネントだけが更新される設計です。

const priceAtom = atom(1000)
const quantityAtom = atom(2)

const totalPriceAtom = atom((get) => {
  const price = get(priceAtom)
  const quantity = get(quantityAtom)

  return price * quantity
})

この例では、priceAtomまたはquantityAtomが変更されると、totalPriceAtomの値も更新されます。

Reduxでは、まず大きなStateツリーを設計します。

Store
├── user
├── products
├── cart
└── notifications

Jotaiでは、必要な状態をAtomとして定義し、それらを組み合わせます。

userAtom

productsAtom

cartAtom
 ├── cartItemCountAtom
 └── cartTotalPriceAtom

ReduxがトップダウンにState全体を設計する考え方だとすると、Jotaiは小さな状態を積み上げていくボトムアップな設計です。


状態更新の考え方を比較する

3つのライブラリは、状態を更新するときの考え方が異なります。

Redux

Reduxでは、イベントをActionとして表現します。

dispatch(productSelected(productId))

コードを読むときは、次の順番で処理を追います。

dispatch
  ↓
Action
  ↓
Reducer
  ↓
State

「何が起きた結果、Stateが変化したのか」が明確です。


Zustand

Zustandでは、Storeに定義したActionを直接呼び出します。

selectProduct(productId)

コードを読むときは、次の流れになります。

StoreのAction
  ↓
set
  ↓
State

Reduxより流れが短く、処理を追いやすい構造です。


Jotai

Jotaiでは、対象となるAtomを直接更新します。

setSelectedProductId(productId)

コードを読むときは、AtomとAtomの依存関係を確認します。

Atom
  ↓
依存するAtom
  ↓
Component

Jotaiでは、アプリケーション全体のStoreよりも、どのAtomがどのAtomに依存しているかが重要になります。


設計時の違い

Reduxで設計する場合

Reduxでは最初に、アプリケーション全体の状態とイベントを整理します。

どの状態をグローバルに管理するか
        ↓
機能ごとにSliceを分ける
        ↓
どのActionで状態が変わるか決める
        ↓
Reducerを定義する

例えば、顧客管理画面では次のように設計できます。

store
├── authentication
├── customerSearch
├── selectedCustomer
└── notifications

ReduxではStateだけではなく、業務上のイベントも設計します。

customerSearchStarted
customerSearchSucceeded
customerSearchFailed
customerSelected
customerSelectionCleared

状態変化を業務イベントとして表現したい場合に向いています。


Zustandで設計する場合

Zustandでは、どの機能がどの状態と操作を持つかを考えます。

どの状態を共有するか
        ↓
どの機能単位でStoreを作るか
        ↓
Storeが持つ操作を定義する
customerSearchStore
├── keyword
├── searchConditions
├── selectedCustomerId
├── setKeyword
├── selectCustomer
└── reset

Stateと操作をひとまとまりにして設計しやすい点が特徴です。

ただし、次のような巨大Storeを作らないように注意が必要です。

appStore
├── authentication
├── customer
├── modal
├── notification
├── theme
├── search
└── form

機能や責務ごとにStoreを分割するルールが必要です。


Jotaiで設計する場合

Jotaiでは、状態をどこまで小さなAtomに分解するかを考えます。

必要な状態をAtomとして定義する
        ↓
Atom同士の依存関係を作る
        ↓
コンポーネントが必要なAtomを利用する
searchKeywordAtom
selectedPrefectureAtom
searchConditionsAtom
selectedCustomerIdAtom

さらに、既存のAtomから派生したAtomを作れます。

searchKeywordAtom
selectedPrefectureAtom
        ↓
searchConditionsAtom

状態同士の依存関係が多い画面や、細かな状態を必要なコンポーネントだけで共有したい場合に使いやすい設計です。


3つのライブラリを比較する

観点 Redux Toolkit Zustand Jotai
状態の単位 1つのStoreとSlice Store Atom
更新方法 Actionをdispatch Storeの関数を呼ぶ Atomを更新
更新ロジック Reducer set Atomのwrite処理
設計の方向 State全体から分割 機能単位のStore 小さなAtomを合成
Provider Reactでは基本的に必要 基本的に不要 状況により利用
再レンダリング制御 Selector Selector Atomの依存関係
コード量 比較的多い 少ない 少ない
ルール 強い 比較的自由 比較的自由
状態変更の追跡 得意 比較的シンプル Atom単位
向いている規模 中規模から大規模 小規模から中規模 小規模から中規模
チーム開発 統一しやすい 独自ルールが必要 Atom設計のルールが必要

どのライブラリを選ぶか

どの状態管理ライブラリが優れているかではなく、どのように状態を設計したいかで判断します。

Reduxを選ぶ場合

Reduxは、次のような場合に向いています。

  • 状態更新のルールを統一したい
  • 多人数で開発する
  • 業務ロジックが複雑
  • Actionの履歴から状態変化を追いたい
  • 状態管理を一定の構造に揃えたい
  • 大規模なアプリケーションを長期運用する

Reduxはコード量が増えやすい一方で、誰が書いても比較的同じ構造になりやすい点がメリットです。


Zustandを選ぶ場合

Zustandは、次のような場合に向いています。

  • Reduxほど厳密な構造は必要ない
  • シンプルにStoreを作りたい
  • Stateと操作を機能単位でまとめたい
  • 少ないコードで実装したい
  • Reduxに近いSelectorベースの設計を使いたい

Reduxの考え方を保ちながら、ActionやReducerの仕組みを簡略化したい場合に選びやすいライブラリです。


Jotaiを選ぶ場合

Jotaiは、次のような場合に向いています。

  • 状態を小さな単位で管理したい
  • 状態同士を組み合わせたい
  • コンポーネントごとに必要な状態だけ購読したい
  • 大きなStoreを最初に設計したくない
  • ReactのuseStateに近い感覚で状態を共有したい

画面内に細かな状態が多く、それぞれの状態に依存関係がある場合に使いやすいライブラリです。


まとめ

Redux、Zustand、Jotaiの違いを簡単に表すと、次のようになります。

Redux
状態の変更をActionとReducerで管理する

Zustand
機能ごとのStoreに状態と操作をまとめる

Jotai
小さなAtomを組み合わせて状態を作る

Reduxは、状態変更の流れを明確にし、アプリケーション全体に統一したルールを持たせる設計です。

ZustandはReduxと似たイミュータブルな状態モデルとSelectorの考え方を持ちながら、ActionやReducerを必須とせず、より直接的に状態を更新します。

Jotaiは、単一のStoreを中心に考えるのではなく、小さなAtomとその依存関係を組み合わせて状態を設計します。

設計するときは、次のように考えると整理しやすくなります。

状態更新のルールと履歴を重視する
→ Redux

シンプルなStoreと少ないコードを重視する
→ Zustand

小さな状態の組み合わせを重視する
→ Jotai

Reduxはルールを先に設計し、Zustandは機能単位のStoreを設計し、Jotaiは状態同士の依存関係を設計します。

この設計思想の違いを理解することが、ライブラリを選ぶうえで最も重要です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?