mcpField
Z
zustand-state-management

zustand-state-management

github.com/fixmyberlin開発059 回インストール1 日前に更新
リポジトリ

zustand-state-management について

React アプリで Zustand v5 を使うための開発スキルです。小さなストア、カスタムフック、セレクターの設計に加え、クライアント UI 状態とサーバー・URL 状態の区別を扱います。

主な機能

  1. 01Zustand v5 のストア規約
  2. 02カスタムフックのエクスポート方針
  3. 03アトミックセレクターの指針
  4. 04イベント型アクションの設計
  5. 05サーバー・URL 状態との区分

活用シーン

  1. 01コンポーネント間の UI 状態共有
  2. 02一時的なクライアント設定の保存
  3. 03カスタムフックでの TanStack Query 連携
  4. 04機能単位のストア構成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/fixmyberlin/fixmyskills --skill zustand-state-management

インストール後、Claude Code で/zustand-state-managementを入力して読み込まれたか確認します。

詳細

LLM リファレンス: ドキュメントの目次と最新の API を確認するには、llms.txt を取得してください。全ドキュメント:llms-full.txt。人が読みやすいドキュメント:zustand.docs.pmnd.rs。

基本的な考え方: Zustand の使い方(Dominik Dorfmeister)— カスタムフックのみをエクスポートし、アトミックセレクター、actions 名前空間、イベント形式のアクション、多数の小さなストアを使用し、カスタムフックを介して Query/URL と組み合わせます。

バージョン: Zustand v5。アプリでは zustand@^5 に固定してください。アップグレード時は v5 への移行を確認してください。


Zustand を使う場面

Zustand を使う対象別のものを使う対象
コンポーネント間で共有するクライアント UI の状態(パネル、地図ツール、ウィザードのステップ)サーバーデータ → TanStack Query
URL に含めない一時的なクライアント設定共有可能な状態/URL の状態 → ルーターの検索パラメーター(Router を使わない Vite アプリ:nuqs)。Zustand で重複して管理しないこと
小規模で同期的なクライアント状態認証セッション → スキル tanstack-start-auth

アプリの状態の多くは、サーバーまたは URL の状態です。すでに別の方法で管理されている状態ではない、クライアント全体で使う状態が必要な場合にのみ、Zustand ストアを追加してください。


ファイル名とエクスポート名

ストアファイル 1 つにつき、関心事は 1 つです。 機能と同じ場所に配置します(Start のレイアウトについては tanstack-start-conventions を参照。SPA アプリでは components//shared/ の下に機能ごとのフォルダーを配置します)。

項目規約例
ファイル{domain}-store.ts(ケバブケース、末尾に -store)map-filters-store.ts
フォルダー機能の隣。例:src/features/map/共有されている場合を除き、全ストアを単一の stores/ にまとめない
状態の型{Domain}Store(パスカルケースのインターフェース)MapFiltersStore
内部の create フックuse{Domain}Store — エクスポートしないことuseMapFiltersStore
エクスポートするフック状態のプリミティブには use{Slice}、actions には use{Domain}ActionsuseAppliedFilters、useMapFiltersActions

使用しないもの: store.ts、state.ts、zustand.ts、useMapFiltersStore.ts(ファイル名から生のストアをエクスポートすると誤解されるため)。関係のないドメインを 1 つのファイルにまとめないでください。

永続化: ストアごとに一意の name を指定し、ファイル名に合わせます。例:map-filters-store.ts には fmc-map-filters を指定します。TanStack Start の SSR + persist: スキル tanstack-start-conventions と llms.txt → SSR and Hydration に従ってください(ハイドレーションゲートまたは公式の SSR セーフなパターン)。


標準的なストアの形

import { create } from 'zustand'

interface MapFiltersStore {
  applied: string[]
  actions: {
    addFilter: (filter: string) => void
    clearFilters: () => void
  }
}

const useMapFiltersStore = create<MapFiltersStore>()((set) => ({
  applied: [],
  actions: {
    addFilter: (filter) =>
      set((state) => (state.applied.includes(filter) ? state : { applied: [...state.applied, filter] })),
    clearFilters: () => set({ applied: [] }),
  },
}))

export const useAppliedFilters = () => useMapFiltersStore((state) => state.applied)

export const useMapFiltersActions = () => useMapFiltersStore((state) => state.actions)

TypeScript: ミドルウェアを使わない場合も、常に create<StoreType>()((set) => …)(二重の括弧)を使用してください。


ルール

  1. カスタムフックのみをエクスポートします(use{Slice} + use{Domain}Actions)。use{Domain}Storeは非公開にします。セレクターを指定せずにストアフックを呼び出さないでください。
  2. プリミティブ値または安定した参照を返すアトミックなセレクターを使い、スライスごとにエクスポートするフックは1つにします。2つの値を同時に必要とすることがまれな場合に限り、useShallow(zustand/shallowから)を使い、可能な限りアトミックなフックを優先します。
  3. actionsを状態から分離します。 actionsの参照は安定しているため、const { addFilter } = useMapFiltersActions()のようにして問題ありません。
  4. アクションはセッターではなくイベントとしてモデル化します。 コンポーネントからsetAppliedを呼び出すのではなく、addFilterやclosePanelのようにします。ビジネスロジックはストアに置きます。高頻度で発生する入力(リサイズ、オブザーバー)では、変更がない場合にsetから以前のstateを返します。
  5. アプリ全体で1つのストアを使うより、小さなストアを多数使います。 カスタムフックで境界部分をまとめます(例:useCredentialsStoreとuseUsersStoreを読み取るフック)。強い理由(TypeScriptの負荷が大きい場合など)がない限り、スライスパターンは避けてください。詳しくはllms.txtを参照してください。
  6. カスタムフックを使ってTanStack Queryと組み合わせます。 フィルターはZustandに、サーバーのリストはQueryに置きます(queryKey: ['todos', filters])。
  7. サーバーから取得したデータにZustandを使わないでください。

llms.txtに委ねる内容

このスキル内でAPIドキュメント全体を重複させないでください。ミドルウェア(persist、devtools、immer。persistはzustand/middlewareからインポートします)、パターン(スライス、状態のリセット、バニラストア、テスト)、連携機能(SSRとHydration、URLハッシュ、Maps/Sets)、v4からv5への移行については、llms.txtを取得してください。


関連スキル

トピックスキル
アプリのレイアウト、SSR(Start)tanstack-start-conventions
URL検索(Router)tanstack-router-conventions
URLクエリ状態(Routerなし)nuqs

コメント