nextjs-zustand について
nextjs-zustandは、Next.js 16 App RouterでZustand v5によるクライアント状態管理を実装するスキルです。リクエストごとに分離するContextストア、ハイドレーション、ミドルウェア構成、TypeScriptでのファイル整理を扱います。
主な機能
- 01Zustand v5のカリー化構文を使用
- 02ContextでApp Routerのストアを分離
- 03devtools・persist・immerを合成
- 04永続状態の手動再ハイドレーション
- 05セレクターにuseShallowを適用
- 06機能別のストアとファイル構成
活用シーン
- 01Client Components間でUI状態を共有
- 02App Routerでリクエスト分離ストアを作成
- 03テーマやカートなどの状態を永続化
- 04SSRとクライアントの不整合を防止
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ fusengine/ agents --skill nextjs-zustandインストール後、Claude Code で/nextjs-zustandを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/auto-selectors.mdhydration.mdinstallation.mdmiddleware.mdmigration-v5.mdnextjs-integration.mdreset-state.mdslices.mdstore-patterns.mdsubscribe-api.mdtesting.mdtypescript.md詳細
persist ミドルウェアでの skipHydration と、SSR の不一致を避けるための useEffect 内での手動再ハイドレーション、配列/オブジェクトのセレクター向けの useShallow、SOLID に基づくファイル構成(store.ts、store-provider.tsx、use-store.ts)を扱います。Zustand はクライアントコンポーネント専用であり、サーバーコンポーネントでは決して使用しないこと(代わりにそこでデータを直接取得します)、認証トークンの永続化には決して使用しないこと(httpOnly Cookie を使用します)を明記します。サーバー状態のキャッシュは対象外です(その場合は nextjs-tanstack-query を参照してください)。
Next.js 16 向け Zustand
React 18 以降の useSyncExternalStore を使った、最小限で拡張性の高い状態管理です。
エージェントのワークフロー(必須)
実装を始める前に、必ず 3 つのエージェントを並行して起動してください。それぞれ 1 回の Agent 呼び出しで、name を指定します。
- fuse-ai-pilot:explore-codebase - 既存のストアと状態管理のパターンを分析します
- fuse-ai-pilot:research-expert - Context7/Exa を使って最新の Zustand v5 ドキュメントを確認します
- mcp__context7__query-docs - ミドルウェアと TypeScript のパターンを確認します
実装後、検証のために fuse-ai-pilot:sniper を実行してください。
概要
使用する場面
- Next.js App Router アプリケーションでクライアントサイドの状態を管理する場合
- クライアントコンポーネント間だけでグローバル状態を共有する必要がある場合
- 状態を localStorage/sessionStorage に永続化する場合
- UI の状態(モーダル、サイドバー、テーマ、カート)を構築する場合
- 複雑な状態管理で React Context を置き換える場合
Zustand v5 を選ぶ理由
| 機能 | メリット |
|---|---|
| 最小限の API | シンプルな create() 関数で、ボイラープレートが不要です |
| React 18 ネイティブ | useSyncExternalStore を使用し、シムは不要です |
| TypeScript を第一に設計 | カリー化パターンにより、完全な型推論が得られます |
| ミドルウェアのスタック | devtools、persist、immer を組み合わせられます |
| バンドルサイズ | gzip 圧縮後で約 2 KB と、最小クラスの状態管理ライブラリです |
| プロバイダー不要 | Context ラッパーなしで、ストアに直接アクセスできます |
重要なルール
- クライアントコンポーネント専用 - Zustand をサーバーコンポーネントで使用しないでください
- App Router では Context パターンを使用 - グローバルストアを避けます(リクエストの分離)
- 配列/オブジェクトには useShallow を使用 - 不要な再レンダリングを防ぎます
- persist では skipHydration を使用 - SSR との互換性に必須です
- v5 のカリー化構文 -
create<State>()((set) => ({...})) - SOLID に基づくパス - ストアは
modules/[feature]/src/stores/に配置します
SOLID アーキテクチャ
モジュール構成
ストアは機能モジュールごとに整理します。
modules/cores/stores/- 共有ストア(テーマ、UI)modules/auth/src/stores/- 認証状態modules/cart/src/stores/- カートの状態modules/[feature]/src/interfaces/- ストアの型
ファイル構成
| ファイル | 用途 | 最大行数 |
|---|---|---|
store.ts | create() によるストアの作成 | 50 |
store.interface.ts | TypeScript インターフェース | 30 |
store-provider.tsx | Context プロバイダー(App Router) | 40 |
use-store.ts | セレクターを備えたカスタムフック | 20 |
主な概念
ストアの作成(v5 構文)
TypeScript の型推論には二重括弧が必要です。カリー化パターンにより、完全な型安全性が確保されます。
Context ベースのストア
Next.js App Router では、リクエスト間でストアが共有されないよう、ストアを Context でラップします。初期化には useRef と zustand/vanilla の createStore を使用します。
ミドルウェアの合成
ミドルウェアを devtools → persist → immer の順にスタックします。順序は TypeScript の型に影響します。
ハイドレーションの処理
persist ミドルウェアで skipHydration: true を使用します。SSR の不一致を避けるため、useEffect 内で手動再ハイドレーションを行います。
リファレンスガイド
| 必要な項目 | リファレンス |
|---|---|
| 初期設定 | installation.md |
| ストアのパターン | store-patterns.md |
| SSR/ハイドレーション | hydration.md |
| ミドルウェア | middleware.md |
| Next.js App Router | nextjs-integration.md |
| TypeScript | typescript.md |
| スライスパターン | slices.md |
| 自動セレクター | auto-selectors.md |
| 状態のリセット | reset-state.md |
| Subscribe API | subscribe-api.md |
| テスト | testing.md |
| v4 から v5 への移行 | migration-v5.md |
ベストプラクティス
- セレクターパターン - パフォーマンスのため、常に
useStore((s) => s.field)を使用します - useShallow - 再レンダリングを防ぐため、配列/オブジェクトのセレクターをラップします
- ストアを分ける - ドメインごとに1つのストアを用意します(認証、カート、UI、テーマ)
- サーバーデータは別の場所で管理する - サーバー状態には TanStack Query を使用します
- 開発時のみ DevTools を使用する - process.env のチェックで DevTools をラップします
- persist の対象を限定する - 必要なフィールドのみを永続化し、トークンは決して永続化しません
禁止されているパターン
| パターン | 理由 | 代替案 |
|---|---|---|
| App Router でのグローバルストア | ユーザー間でリクエストが共有されます | コンテキストベースのストア |
| Server Components での Zustand | RSC では React フックを使用できません | データを直接取得する |
| 認証トークンの永続化 | セキュリティ上の脆弱性 | httpOnly クッキー |
| オブジェクトに useShallow を使用しない | 過剰な再レンダリング | useShallow(selector) |
| v4 の構文 | TypeScript の型推論が壊れます | v5 のカリー化 create<T>()() |