zustand-pro
SKILL.md
Zustand Pro -- State Management for Next.js 16
When to Use
Trigger on any mention of: zustand, global state, store, state management, persist middleware, immer, devtools, CV editor state, multi-step form state, undo/redo.
Reference Files
Load the relevant reference file(s) based on the task:
| File | Lines | Content |
|---|---|---|
references/setup.md |
~65 | Version compatibility matrix (v4/v5), breaking changes, React 19 notes, install, project structure |
references/core-api.md |
~100 | create, createStore, useStore, setState, subscribe, selectors |
references/nextjs-patterns.md |
~190 | 3 patterns: global store, per-request context provider (SSR), hydration-safe persist, server component rules |
references/typescript.md |
~115 | Basic typed store, middleware typing, slices pattern (large stores), typed selectors |
references/middleware.md |
~195 | persist, devtools, immer, subscribeWithSelector, combine, composition order |
references/errors-001-010.md |
~200 | ZST-001 to ZST-010: hydration, infinite re-render, server component, state sync, TS middleware, SSR storage, useShallow, devtools, persist schema, async actions |
references/errors-011-020.md |
~175 | ZST-011 to ZST-020: missing provider, immer import, fast refresh, slices+middleware TS, persist+immer merge, React Compiler naming, subscribeWithSelector, setState replace, window undefined, stale closure |
references/cviet-patterns.md |
~190 | Full multi-step CV editor store with devtools+subscribeWithSelector+immer, navigation, CRUD for all CV sections, AI patch, saving |
references/cviet-hooks.md |
~170 | Auto-save with debounce, undo/redo (zundo), AI panel integration, unsaved changes warning |
references/performance.md |
~130 | Atomic selectors, useShallow, stable action refs, transient updates, computed/derived state, selector extraction |
references/testing.md |
~155 | Jest auto-reset mock, Vitest auto-reset mock, store direct testing, component testing, pre-set state testing |
references/anti-patterns.md |
~170 | 6 anti-patterns (server component store, full store select, store in component, direct mutation, server state, missing useShallow) + 3 gotchas (middleware order, Set/Map persist, getState reactivity) |
references/ecosystem.md |
~85 | Zustand vs Redux vs Jotai comparison, why Zustand for CViet, third-party middleware (zundo, zustand-computed, zukeeper), key links, quick reference card |
Error Quick Lookup
| ID | Error | Fix |
|---|---|---|
| ZST-001 | Hydration mismatch with persist | skipHydration + useHydratedStore hook |
| ZST-002 | Infinite re-render (v5) | Use useShallow or stable selector |
| ZST-003 | Hook in Server Component | Move to Client Component with 'use client' |
| ZST-004 | State not updating across components | Immutable update or check import path |
| ZST-005 | TypeScript error with middleware | Use curried create<Type>()(...) form |
| ZST-006 | Persist storage unavailable (SSR) | Guard with typeof window check |
| ZST-007 | useShallow import not found |
Import from zustand/shallow (v5) |
| ZST-008 | DevTools not showing store | Add devtools middleware with name |
| ZST-009 | Persist overwrites new fields | Add version + migrate to persist config |
| ZST-010 | Async action not updating | Use set() after await, not direct mutation |
| ZST-011 | Cannot read getState (undefined) | Wrap component tree in Provider |
| ZST-012 | Immer not working | Import from zustand/middleware/immer |
| ZST-013 | Multiple store instances (dev) | Expected in dev; use persist for preservation |
| ZST-014 | TS error with slices + middleware | Declare middleware mutators in StateCreator |
| ZST-015 | Persist + immer deep merge conflict | Custom merge function with structuredClone |
| ZST-016 | React Compiler use prefix warning |
Name stores useXxxStore |
| ZST-017 | subscribeWithSelector fires always | Provide equalityFn or stable selector |
| ZST-018 | setState replace missing fields (v5) | Provide ALL fields or use partial update |
| ZST-019 | "window is not defined" | Guard persist storage with typeof window |
| ZST-020 | Stale closure in useEffect | Use subscribe or getState() in effect |
Key Patterns
Store Creation (Next.js 16)
// src/stores/cv-editor-store.ts
'use client' // Not needed for store file, but consumers must be client
import { create } from 'zustand'
import { persist, devtools, immer } from 'zustand/middleware'
// Middleware order matters: devtools(persist(immer(...)))
Hydration-Safe Persist
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
const useStore = create(persist((...) => ({...}), {
name: 'cv-draft',
skipHydration: true, // Critical for Next.js SSR
}))
// In client component:
useEffect(() => { useStore.persist.rehydrate() }, [])
useShallow for Multi-Value Selectors
import { useShallow } from 'zustand/shallow'
const { name, email } = useStore(
useShallow((s) => ({ name: s.name, email: s.email }))
)
Middleware Composition Order
devtools -> subscribeWithSelector -> persist -> immer -> stateCreator
Weekly Installs
1
Repository
clownnvd/claude…e-skillsFirst Seen
6 days ago
Security Audits
Installed on
zencoder1
amp1
cline1
openclaw1
opencode1
cursor1