© TOOLS BOX — Next.js / React / TypeScript コードサンプル集

サンプルガイド
←サンプル一覧
nextjsstate-management

Zustand Test の devtools をアクション命名規則で読みやすくする

store 名 / アクション名 / replace モードを揃え、Redux DevTools のタイムラインを 4 store 横断で読み解けるようにする命名規則を解説する。

難易度: 中級·更新: 2026-05-07·
zustand

対応バージョン

nextjs 15react 19zustand 5

前提環境

Zustand の create と middleware を理解していること。Redux DevTools Extension をインストール済みであること

概要

Zustand Test は 4 つの store を持つため、devtools の名前と action 名を雑に書くと 「タイムラインに setState が並ぶだけ」 で何が起きたか追えなくなります。 本記事では、Playground で採用している命名規則を 4 つに分けて整理します。

場所何を書くか
devtools(..., { name: "..." })DevTools 上での store 識別名
set(values, false, "actionName")1 つ 1 つの アクション名
set(initial, true, "reset")replace モード(merge ではなく置き換え)
既存 action の 派生・補助setX:byY のように 1 トークンに圧縮

インストール

npm install zustand

Chrome 拡張の Redux DevTools Extension もインストールしておきます(DevTools の Redux タブから開きます)。

store 名は PascalCase で揃える

DevTools は複数の store を タブで切り替える UI で表示します。名前を揃えておくと並んだときに読みやすくなります。

import { create } from "zustand";
import { devtools } from "zustand/middleware";

export const useSettingsStore = create<SettingsState>()(
  devtools((set) => ({ /* ... */ }), { name: "SettingsStore" })
);
export const useProfileStore  = create<ProfileState>()(
  devtools((set) => ({ /* ... */ }), { name: "ProfileStore" })
);
export const useDetailStore   = create<DetailState>()(
  devtools((set) => ({ /* ... */ }), { name: "DetailStore" })
);
export const useUiStore       = create<UiState>()(
  devtools((set) => ({ /* ... */ }), { name: "UiStore" })
);

useFooStore の Foo 部分を FooStore として揃える だけで、DevTools での識別が一気に楽になります。

アクション名は 動詞 + 対象 を基本にする

set の第 3 引数にアクション名を渡すと、タイムラインに表示されます。命名規則を作っておくと、流れがそのまま読めます。

patchFormData: (partial) => set(partial,           false, "patchFormData"),
setFormData:   (values)  => set(values,            false, "setFormData"),
reset:         ()        => set(INITIAL_SETTINGS,  true,  "reset"),

推奨は次のとおり。

  • 基本: 動詞 + 対象(setFormData / setSuggestedRate / setTab)
  • 部分更新: patch + 対象(patchFormData)
  • 派生・条件付き: 動詞 + 対象 + コロン + 修飾(setSuggestedRate:fromSettings のように)
  • リセット: reset だけで OK。store 名で識別が付く

storeSync 経由で書き込まれた action は 由来を明示 すると追いやすくなります。

useDetailStore.getState().setSuggestedRate(next);
// ↓ detailStore 側
setSuggestedRate: (rate) => set({ suggestedRate: rate }, false, "setSuggestedRate:fromSettings"),

ただし、複数の由来を区別する必要が無いなら コロン修飾は付けない方がノイズが少ない です。Playground では suggestedRate だけ修飾を付けています。

replace モードを使い分ける

set の 第 2 引数 が replace フラグです。true を渡すと merge ではなく 置き換え になります。

第2引数挙動使う場面
false (デフォルト)部分マージsetFormData / patchFormData / 通常更新
true全置き換えreset / 初期化など state 形が変わるとき
reset: () => set(INITIAL_SETTINGS, true, "reset"),

reset を merge にしてしまうと、reset 後に古いキーが残るリスクがあります。state 形を初期値そのものに戻したい ときは必ず true を渡しましょう。

派生 store の整合を保つ書き込み

storeSync のリスナーから set するアクションは「由来は別 store の変化 だ」とアクション名で示します。これにより、DevTools のタイムラインで「どの store の変化が連鎖を起こしたか」を追跡できます。

// settings → detail(suggestedRate)
useSettingsStore.subscribe(
  (s) => s.rate,
  (rate) => {
    const next = Math.max(0, rate * 1.1);
    useDetailStore.getState().setSuggestedRate(next);
  }
);

タイムライン上の見え方:

SettingsStore  patchFormData       { rate: 50 }
DetailStore    setSuggestedRate    { suggestedRate: 55 }

連鎖が 2 行で読める ように命名しておくのが目標です。

タイムトラベルで再現するときの注意

DevTools の「Jump」(時間旅行)は state を その時点に戻すだけ で、subscribe のリスナーは再実行しません。

  • ✅ できる: 過去の state を表示状態として再現する
  • ❌ できない: 過去の state から storeSync を 再シミュレーション する

挙動を再現したいときは、UI 操作をやり直す(reset から始め直す)方が確実です。Playground に「全ストアをリセット」ボタンを置いているのは、DevTools での検証フローを楽にする目的もあります。

ポイント

  • store 名は <Domain>Store の PascalCase で統一する。DevTools のタブが揃って読みやすくなる
  • アクション名は 動詞 + 対象 を基本に、patch / reset / :from修飾 を補助で使う
  • set の第 2 引数は reset でだけ true(replace モード)にする。state 形を初期値に戻すため
  • storeSync 経由の書き込みは由来をアクション名で示す。DevTools 上で 連鎖が 2 行で読める よう設計する
  • DevTools のタイムトラベルは subscribe を再実行しない。再現性が要るならリセットからやり直す

関連記事

セットで読むと文脈がつながる関連記事は次のとおりです。

  • Zustand 編 — devtools と subscribeWithSelector を併用する場合の middleware 順序
  • storeSync テスト編 — タイムラインの代わりにテストで連鎖を固定する
  • アクション受け渡しパターン編 — selector で取り出すアクションの参照安定性
  • Zustand Test (Build) — 完成例と外部デモ

注意点

Playground 追加記事。devtools の name オプション・set の第3引数・replace モードを揃えると、複数 store のタイムラインが一気に読みやすくなる。

リポジトリを見る

関連サンプル

同じテーマや技術スタックを使った実装例

  • Zustand Test の 4 ストア設計と storeSync を読み解く

    settings / profile / detail / ui の 4 ストアを subscribe で連携し、patchFormData・setFormData・reset を使い分ける Playground の Zustand 実装を1ステップずつ解説する。

  • Zustand Test のアクションを selector → props で安全に受け渡す

    Zustand のアクションは store 生成時から参照が安定している性質を活かし、selector で取り出して props で子に渡す書き方を解説する。

  • Zustand Test の保存処理を非同期 action と loading / error 状態で扱う

    saveSettings のような非同期処理を store のアクションに閉じ込め、status: 'idle'|'loading'|'error'|'success' を 1 つのフィールドで表現する書き方を解説する。

  • Zustand Test の settingsStore を BroadcastChannel で複数タブに同期する

    BroadcastChannel API で別タブの settingsStore に変更をブロードキャストし、エコーバックを避けながら受信側を更新する手順を解説する。

  • Zustand Test の suggestedRate を subscribeWithSelector で派生する

    settingsStore.rate から detailStore.suggestedRate を導出する派生状態の作り方を、subscribeWithSelector と shallow を軸に解説する。

関連仕様

このサンプルを理解するのに役立つ仕様や概念

  • FrameworkNext.jsReact ベースのフルスタックフレームワーク。SSR・SSG・App Router・API Routes を提供する。
←サンプル一覧に戻る