🦫

🦫 Zustand入門してみた

に公開

Zustand(ズスタンド)とは

Reactアプリで「状態(state)」をシンプルに・安全に・直感的に扱うためのライブラリ。

たとえば、

「グローバルに count を共有して、どのコンポーネントからでも増減したい」

というときに、useState だけではスコープが狭く、Redux は重すぎる。

→ そんなときに Zustand。ありがたい。


⚙️ 基本のイメージ

Store(倉庫)
├─ Counter.tsx …… useCounterStore() を通じて Store を参照
├─ Header.tsx …… useCounterStore() を通じて Store を参照
└─ Footer.tsx …… useCounterStore() を通じて Store を参照

  • Storeはアプリ全体で1つの状態の倉庫
  • 各コンポーネントは「必要な変数・関数だけ」取り出して使う
  • Reactの再レンダーは「その変数を使っている部分だけ」に限定される

⚖️ Zustandのメリット・デメリット

✅ メリット(Pros)

項目 内容 備考
🧩 シンプル create()でstoreを1行で作れる Reduxのようなreducerやactionが不要
⚡️ 軽量・高速 選択的subscribeで無駄な再レンダーなし RecoilやContext APIより速いケース多い
🧠 Hooksベース useStore()で自然に状態取得できる React Hooksの感覚そのまま
🔁 再利用性 Storeを複数作って分離できる 状態管理のスコープを細かく切れる
💾 永続化 localStorage対応(persistミドルウェア) ページ更新してもデータ保持可能
🧮 型安全(TS) TypeScriptと相性抜群 型推論も強力
🔍 DevTools連携 Redux DevToolsが使える 状態履歴の確認も可能

❌ デメリット(Cons)

項目 内容 対応策
⚙️ 構造が自由すぎる 設計パターンを決めておかないとカオスに store命名・責務分離をルール化する
🧱 Contextより低レベル ReactのContext APIのような「自動プロバイダ」がない storeを自分でimportする必要あり
🧩 SSR対応に注意 Hydrationミスに注意(Next.jsなど) useEffect内でクライアント初期化する
🔄 大規模連携が弱い GraphQL・API層との連携を自作する必要 React QueryやSWRと併用が一般的

⚔️ 他ライブラリとの比較

ライブラリ 特徴 適する規模 状態共有の粒度 備考
Zustand 軽量・直感的。Hooksベース。 小〜中規模 高精度(選択的) UI・アニメ・PixiJSにも◎
Redux Toolkit 組織的・拡張性◎ 中〜大規模 中精度 明確なフロー(action→reducer)
Recoil React製。依存関係の追跡が強い 中規模 高精度 部分的state管理に最適
Jotai 最小単位(atom)で状態管理 小〜中規模 高精度 Functional & 直感的
Context API React標準機能 超小規模 低精度 再レンダーが広がりやすい

🧭 簡単にまとめると…

シチュエーション 最適な選択
シンプルにグローバル変数を共有したい ✅ Zustand
大規模アプリでチーム開発 ⚙️ Redux Toolkit
複雑な依存関係・派生stateが多い 🧠 Recoil
個人開発・軽いUI管理 🎯 Jotai or Zustand

🔄 状態の流れ(イメージで理解)

Zustandでは「変数 → 更新 → 反映」の流れが超シンプルです。


🧩 例:カウンターアプリの処理フロー

[1] Store作成
    └ count = 0
       increase() { count++ }
       decrease() { count-- }

[2] UIでボタン押下
    └ onClick → store.increase()

[3] storeのcountが更新
    └ set((state) => ({ count: state.count + 1 }))

[4] Zustandが再レンダーを検知
    └ countを使っているコンポーネントだけ更新

[5] UI反映
    └ <h1>Count: 1</h1>

📈 Reduxとの違い

Reduxは「action → reducer → dispatch → state更新 → subscribe」と5段階だが、

Zustandは「set → state更新 → 自動通知」のわずか3ステップ


処理の流れ

[1] UIでshape選択 → store.setShape("square")
[2] 状態が更新され、Canvas描画コンポーネントが自動再レンダー
[3] 「開始」ボタン押下 → store.toggleSimulation()
[4] 状態が true に変わり、PixiJSが開始される
[5] 停止ボタン → toggleSimulation() → false に戻る

➡️ PixiJSやThree.jsのようなリアルタイム描画とも親和性が高い

状態をFluxライクに扱えるのがZustandの真骨頂。


🧾 まとめ(Zustandが選ばれる理由)

観点 理由
🚀 軽量・高速 Contextより10〜30倍速いケースも
🧠 学習コスト 5分で導入可能。Hooks感覚でOK
🧩 柔軟性 storeを複数に分けられる(UI用・API用など)
💾 永続化 localStorageで状態保持可能
🔧 DevTools Redux DevToolsでデバッグ容易
🧍‍♂️ 個人開発〜小チーム開発 構造が直感的でコードが短い

Discussion