zustand-state-management

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Zustand State Management

Zustand 状态管理

Status: Production Ready ✅ Last Updated: 2025-10-24 Latest Version: zustand@5.0.8 Dependencies: React 18+, TypeScript 5+

状态:已就绪可用于生产环境 ✅ 最后更新:2025-10-24 最新版本:zustand@5.0.8 依赖项:React 18+, TypeScript 5+

Quick Start (3 Minutes)

快速开始(3分钟)

1. Install Zustand

1. 安装Zustand

bash
npm install zustand
bash
npm install zustand

or

or

pnpm add zustand
pnpm add zustand

or

or

yarn add zustand

**Why Zustand?**
- Minimal API: Only 1 function to learn (`create`)
- No boilerplate: No providers, reducers, or actions
- TypeScript-first: Excellent type inference
- Fast: Fine-grained subscriptions prevent unnecessary re-renders
- Flexible: Middleware for persistence, devtools, and more
yarn add zustand

**为什么选择Zustand?**
- 极简API:只需学习一个函数(`create`)
- 无冗余模板:无需Provider、Reducer或Action
- TypeScript优先:出色的类型推断
- 高性能:细粒度订阅避免不必要的重渲染
- 灵活性:支持持久化、开发者工具等中间件

2. Create Your First Store (TypeScript)

2. 创建你的第一个Store(TypeScript)

typescript
import { create } from 'zustand'

interface BearStore {
  bears: number
  increase: (by: number) => void
  reset: () => void
}

const useBearStore = create<BearStore>()((set) => ({
  bears: 0,
  increase: (by) => set((state) => ({ bears: state.bears + by })),
  reset: () => set({ bears: 0 }),
}))
CRITICAL: Notice the double parentheses
create<T>()()
- this is required for TypeScript with middleware.
typescript
import { create } from 'zustand'

interface BearStore {
  bears: number
  increase: (by: number) => void
  reset: () => void
}

const useBearStore = create<BearStore>()((set) => ({
  bears: 0,
  increase: (by) => set((state) => ({ bears: state.bears + by })),
  reset: () => set({ bears: 0 }),
}))
关键注意点:注意这里的双括号
create<T>()()
- 这是TypeScript结合中间件使用时的必填语法。

3. Use Store in Components

3. 在组件中使用Store

tsx
import { useBearStore } from './store'

function BearCounter() {
  const bears = useBearStore((state) => state.bears)
  return <h1>{bears} around here...</h1>
}

function Controls() {
  const increase = useBearStore((state) => state.increase)
  return <button onClick={() => increase(1)}>Add bear</button>
}
Why this works:
  • Components only re-render when their selected state changes
  • No Context providers needed
  • Selector function extracts specific state slice

tsx
import { useBearStore } from './store'

function BearCounter() {
  const bears = useBearStore((state) => state.bears)
  return <h1>{bears} 只熊在这里...</h1>
}

function Controls() {
  const increase = useBearStore((state) => state.increase)
  return <button onClick={() => increase(1)}>添加一只熊</button>
}
为什么这样可行:
  • 组件仅在其选中的状态变化时才会重渲染
  • 无需Context Provider
  • 选择器函数提取特定的状态切片

The 3-Pattern Setup Process

三种设置模式

Pattern 1: Basic Store (JavaScript)

模式1:基础Store(JavaScript)

For simple use cases without TypeScript:
javascript
import { create } from 'zustand'

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}))
When to use:
  • Prototyping
  • Small apps
  • No TypeScript in project
适用于不使用TypeScript的简单场景:
javascript
import { create } from 'zustand'

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}))
适用场景:
  • 快速原型开发
  • 小型应用
  • 项目未使用TypeScript

Pattern 2: TypeScript Store (Recommended)

模式2:TypeScript Store(推荐)

For production apps with type safety:
typescript
import { create } from 'zustand'

// Define store interface
interface CounterStore {
  count: number
  increment: () => void
  decrement: () => void
}

// Create typed store
const useCounterStore = create<CounterStore>()((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}))
Key Points:
  • Separate interface for state + actions
  • Use
    create<T>()()
    syntax (currying for middleware)
  • Full IDE autocomplete and type checking
适用于需要类型安全的生产环境应用:
typescript
import { create } from 'zustand'

// 定义Store接口
interface CounterStore {
  count: number
  increment: () => void
  decrement: () => void
}

// 创建类型化Store
const useCounterStore = create<CounterStore>()((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}))
核心要点:
  • 为状态和动作定义独立的接口
  • 使用
    create<T>()()
    语法(为中间件支持的柯里化写法)
  • 完整的IDE自动补全和类型检查

Pattern 3: Persistent Store

模式3:持久化Store

For state that survives page reloads:
typescript
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

interface UserPreferences {
  theme: 'light' | 'dark' | 'system'
  language: string
  setTheme: (theme: UserPreferences['theme']) => void
  setLanguage: (language: string) => void
}

const usePreferencesStore = create<UserPreferences>()(
  persist(
    (set) => ({
      theme: 'system',
      language: 'en',
      setTheme: (theme) => set({ theme }),
      setLanguage: (language) => set({ language }),
    }),
    {
      name: 'user-preferences', // unique name in localStorage
      storage: createJSONStorage(() => localStorage), // optional: defaults to localStorage
    },
  ),
)
Why this matters:
  • State automatically saved to localStorage
  • Restored on page reload
  • Works with sessionStorage too
  • Handles serialization automatically

适用于需要跨页面刷新保留的状态:
typescript
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

interface UserPreferences {
  theme: 'light' | 'dark' | 'system'
  language: string
  setTheme: (theme: UserPreferences['theme']) => void
  setLanguage: (language: string) => void
}

const usePreferencesStore = create<UserPreferences>()(
  persist(
    (set) => ({
      theme: 'system',
      language: 'en',
      setTheme: (theme) => set({ theme }),
      setLanguage: (language) => set({ language }),
    }),
    {
      name: 'user-preferences', // localStorage中的唯一名称
      storage: createJSONStorage(() => localStorage), // 可选:默认使用localStorage
    },
  ),
)
重要性:
  • 状态自动保存到localStorage
  • 页面刷新时自动恢复
  • 同样支持sessionStorage
  • 自动处理序列化

Critical Rules

关键规则

Always Do

务必遵守

✅ Use
create<T>()()
(double parentheses) in TypeScript for middleware compatibility ✅ Define separate interfaces for state and actions ✅ Use selector functions to extract specific state slices ✅ Use
set
with updater functions for derived state:
set((state) => ({ count: state.count + 1 }))
✅ Use unique names for persist middleware storage keys ✅ Handle Next.js hydration with
hasHydrated
flag pattern ✅ Use
shallow
for selecting multiple values ✅ Keep actions pure (no side effects except state updates)
✅ 在TypeScript中使用
create<T>()()
(双括号)以兼容中间件 ✅ 为状态和动作定义独立的接口 ✅ 使用选择器函数提取特定的状态切片 ✅ 对派生状态使用带更新器函数的
set
set((state) => ({ count: state.count + 1 }))
✅ 为持久化中间件的存储键使用唯一名称 ✅ 使用
hasHydrated
标志模式处理Next.js hydration ✅ 选择多个值时使用
shallow
✅ 保持动作纯函数(除了状态更新外无副作用)

Never Do

切勿执行

❌ Use
create<T>(...)
(single parentheses) in TypeScript - breaks middleware types ❌ Mutate state directly:
set((state) => { state.count++; return state })
- use immutable updates ❌ Create new objects in selectors:
useStore((state) => ({ a: state.a }))
- causes infinite renders ❌ Use same storage name for multiple stores - causes data collisions ❌ Access localStorage during SSR without hydration check ❌ Use Zustand for server state - use TanStack Query instead ❌ Export store instance directly - always export the hook

❌ 在TypeScript中使用
create<T>(...)
(单括号)- 会破坏中间件类型 ❌ 直接修改状态:
set((state) => { state.count++; return state })
- 使用不可变更新 ❌ 在选择器中创建新对象:
useStore((state) => ({ a: state.a }))
- 会导致无限渲染 ❌ 为多个Store使用相同的存储名称 - 会导致数据冲突 ❌ 在SSR期间未进行hydration检查就访问localStorage ❌ 使用Zustand管理服务端状态 - 改用TanStack Query ❌ 直接导出Store实例 - 始终导出Hook

Known Issues Prevention

已知问题预防

This skill prevents 5 documented issues:
本技能可预防5个已记录的问题:

Issue #1: Next.js Hydration Mismatch

问题1:Next.js Hydration不匹配

Error:
"Text content does not match server-rendered HTML"
or
"Hydration failed"
Source:
Why It Happens: Persist middleware reads from localStorage on client but not on server, causing state mismatch.
Prevention:
typescript
import { create } from 'zustand'
import { persist } from 'zustand/middleware'

interface StoreWithHydration {
  count: number
  _hasHydrated: boolean
  setHasHydrated: (hydrated: boolean) => void
  increase: () => void
}

const useStore = create<StoreWithHydration>()(
  persist(
    (set) => ({
      count: 0,
      _hasHydrated: false,
      setHasHydrated: (hydrated) => set({ _hasHydrated: hydrated }),
      increase: () => set((state) => ({ count: state.count + 1 })),
    }),
    {
      name: 'my-store',
      onRehydrateStorage: () => (state) => {
        state?.setHasHydrated(true)
      },
    },
  ),
)

// In component
function MyComponent() {
  const hasHydrated = useStore((state) => state._hasHydrated)

  if (!hasHydrated) {
    return <div>Loading...</div>
  }

  // Now safe to render with persisted state
  return <ActualContent />
}
错误信息
"Text content does not match server-rendered HTML"
"Hydration failed"
来源:
原因: 持久化中间件在客户端读取localStorage,但在服务端不会,导致状态不匹配。
解决方案:
typescript
import { create } from 'zustand'
import { persist } from 'zustand/middleware'

interface StoreWithHydration {
  count: number
  _hasHydrated: boolean
  setHasHydrated: (hydrated: boolean) => void
  increase: () => void
}

const useStore = create<StoreWithHydration>()(
  persist(
    (set) => ({
      count: 0,
      _hasHydrated: false,
      setHasHydrated: (hydrated) => set({ _hasHydrated: hydrated }),
      increase: () => set((state) => ({ count: state.count + 1 })),
    }),
    {
      name: 'my-store',
      onRehydrateStorage: () => (state) => {
        state?.setHasHydrated(true)
      },
    },
  ),
)

// 在组件中使用
function MyComponent() {
  const hasHydrated = useStore((state) => state._hasHydrated)

  if (!hasHydrated) {
    return <div>加载中...</div>
  }

  // 现在可以安全地使用持久化状态渲染
  return <ActualContent />
}

Issue #2: TypeScript Double Parentheses Missing

问题2:TypeScript双括号缺失

Error: Type inference fails,
StateCreator
types break with middleware
Why It Happens: The currying syntax
create<T>()()
is required for middleware to work with TypeScript inference.
Prevention:
typescript
// ❌ WRONG - Single parentheses
const useStore = create<MyStore>((set) => ({
  // ...
}))

// ✅ CORRECT - Double parentheses
const useStore = create<MyStore>()((set) => ({
  // ...
}))
Rule: Always use
create<T>()()
in TypeScript, even without middleware (future-proof).
错误信息:类型推断失败,
StateCreator
类型在使用中间件时崩溃
原因: 柯里化语法
create<T>()()
是中间件与TypeScript推断协同工作的必填项。
解决方案:
typescript
// ❌ 错误写法 - 单括号
const useStore = create<MyStore>((set) => ({
  // ...
}))

// ✅ 正确写法 - 双括号
const useStore = create<MyStore>()((set) => ({
  // ...
}))
规则: 即使不使用中间件,在TypeScript中也始终使用
create<T>()()
(面向未来兼容)。

Issue #3: Persist Middleware Import Error

问题3:持久化中间件导入错误

Error:
"Attempted import error: 'createJSONStorage' is not exported from 'zustand/middleware'"
Source: GitHub Discussion #2839
Why It Happens: Wrong import path or version mismatch between zustand and build tools.
Prevention:
typescript
// ✅ CORRECT imports for v5
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

// Verify versions
// zustand@5.0.8 includes createJSONStorage
// zustand@4.x uses different API

// Check your package.json
// "zustand": "^5.0.8"
错误信息
"Attempted import error: 'createJSONStorage' is not exported from 'zustand/middleware'"
来源: GitHub Discussion #2839
原因: 导入路径错误或zustand与构建工具版本不匹配。
解决方案:
typescript
// ✅ v5版本的正确导入
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

// 验证版本
// zustand@5.0.8 包含 createJSONStorage
// zustand@4.x 使用不同的API

// 检查你的package.json
// "zustand": "^5.0.8"

Issue #4: Infinite Render Loop

问题4:无限渲染循环

Error: Component re-renders infinitely, browser freezes
Source: GitHub Discussions #2642
Why It Happens: Creating new object references in selectors causes Zustand to think state changed.
Prevention:
typescript
import { shallow } from 'zustand/shallow'

// ❌ WRONG - Creates new object every time
const { bears, fishes } = useStore((state) => ({
  bears: state.bears,
  fishes: state.fishes,
}))

// ✅ CORRECT Option 1 - Select primitives separately
const bears = useStore((state) => state.bears)
const fishes = useStore((state) => state.fishes)

// ✅ CORRECT Option 2 - Use shallow for multiple values
const { bears, fishes } = useStore(
  (state) => ({ bears: state.bears, fishes: state.fishes }),
  shallow,
)
错误现象:组件无限重渲染,浏览器冻结
来源: GitHub Discussions #2642
原因: 在选择器中创建新对象引用会导致Zustand认为状态已更改。
解决方案:
typescript
import { shallow } from 'zustand/shallow'

// ❌ 错误写法 - 每次创建新对象
const { bears, fishes } = useStore((state) => ({
  bears: state.bears,
  fishes: state.fishes,
}))

// ✅ 正确写法1 - 分别选择原始值
const bears = useStore((state) => state.bears)
const fishes = useStore((state) => state.fishes)

// ✅ 正确写法2 - 选择多个值时使用shallow
const { bears, fishes } = useStore(
  (state) => ({ bears: state.bears, fishes: state.fishes }),
  shallow,
)

Issue #5: Slices Pattern TypeScript Complexity

问题5:切片模式TypeScript复杂度

Error:
StateCreator
types fail to infer, complex middleware types break
Why It Happens: Combining multiple slices requires explicit type annotations for middleware compatibility.
Prevention:
typescript
import { create, StateCreator } from 'zustand'

// Define slice types
interface BearSlice {
  bears: number
  addBear: () => void
}

interface FishSlice {
  fishes: number
  addFish: () => void
}

// Create slices with proper types
const createBearSlice: StateCreator<
  BearSlice & FishSlice,  // Combined store type
  [],                      // Middleware mutators (empty if none)
  [],                      // Chained middleware (empty if none)
  BearSlice               // This slice's type
> = (set) => ({
  bears: 0,
  addBear: () => set((state) => ({ bears: state.bears + 1 })),
})

const createFishSlice: StateCreator<
  BearSlice & FishSlice,
  [],
  [],
  FishSlice
> = (set) => ({
  fishes: 0,
  addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
})

// Combine slices
const useStore = create<BearSlice & FishSlice>()((...a) => ({
  ...createBearSlice(...a),
  ...createFishSlice(...a),
}))

错误信息
StateCreator
类型推断失败,复杂中间件类型崩溃
原因: 组合多个切片需要为中间件兼容性添加显式类型注解。
解决方案:
typescript
import { create, StateCreator } from 'zustand'

// 定义切片类型
interface BearSlice {
  bears: number
  addBear: () => void
}

interface FishSlice {
  fishes: number
  addFish: () => void
}

// 创建带正确类型的切片
const createBearSlice: StateCreator<
  BearSlice & FishSlice,  // 组合后的Store类型
  [],                      // 中间件修改器(无则为空)
  [],                      // 链式中间件(无则为空)
  BearSlice               // 当前切片的类型
> = (set) => ({
  bears: 0,
  addBear: () => set((state) => ({ bears: state.bears + 1 })),
})

const createFishSlice: StateCreator<
  BearSlice & FishSlice,
  [],
  [],
  FishSlice
> = (set) => ({
  fishes: 0,
  addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
})

// 组合切片
const useStore = create<BearSlice & FishSlice>()((...a) => ({
  ...createBearSlice(...a),
  ...createFishSlice(...a),
}))

Middleware Configuration

中间件配置

Persist Middleware (localStorage)

持久化中间件(localStorage)

typescript
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

interface MyStore {
  data: string[]
  addItem: (item: string) => void
}

const useStore = create<MyStore>()(
  persist(
    (set) => ({
      data: [],
      addItem: (item) => set((state) => ({ data: [...state.data, item] })),
    }),
    {
      name: 'my-storage',
      storage: createJSONStorage(() => localStorage),
      partialize: (state) => ({ data: state.data }), // Only persist 'data'
    },
  ),
)
typescript
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

interface MyStore {
  data: string[]
  addItem: (item: string) => void
}

const useStore = create<MyStore>()(
  persist(
    (set) => ({
      data: [],
      addItem: (item) => set((state) => ({ data: [...state.data, item] })),
    }),
    {
      name: 'my-storage',
      storage: createJSONStorage(() => localStorage),
      partialize: (state) => ({ data: state.data }), // 仅持久化'data'
    },
  ),
)

Devtools Middleware (Redux DevTools)

开发者工具中间件(Redux DevTools)

typescript
import { create } from 'zustand'
import { devtools } from 'zustand/middleware'

interface CounterStore {
  count: number
  increment: () => void
}

const useStore = create<CounterStore>()(
  devtools(
    (set) => ({
      count: 0,
      increment: () =>
        set(
          (state) => ({ count: state.count + 1 }),
          undefined,
          'counter/increment', // Action name in DevTools
        ),
    }),
    { name: 'CounterStore' }, // Store name in DevTools
  ),
)
typescript
import { create } from 'zustand'
import { devtools } from 'zustand/middleware'

interface CounterStore {
  count: number
  increment: () => void
}

const useStore = create<CounterStore>()(
  devtools(
    (set) => ({
      count: 0,
      increment: () =>
        set(
          (state) => ({ count: state.count + 1 }),
          undefined,
          'counter/increment', // DevTools中的动作名称
        ),
    }),
    { name: 'CounterStore' }, // DevTools中的Store名称
  ),
)

Combining Multiple Middlewares

组合多个中间件

typescript
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'

const useStore = create<MyStore>()(
  devtools(
    persist(
      (set) => ({
        // store definition
      }),
      { name: 'my-storage' },
    ),
    { name: 'MyStore' },
  ),
)
Order matters:
devtools(persist(...))
shows persist actions in DevTools.

typescript
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'

const useStore = create<MyStore>()(
  devtools(
    persist(
      (set) => ({
        // store定义
      }),
      { name: 'my-storage' },
    ),
    { name: 'MyStore' },
  ),
)
顺序很重要
devtools(persist(...))
会在DevTools中显示持久化动作。

Common Patterns

常见模式

Pattern: Computed/Derived Values

模式:计算/派生值

typescript
interface StoreWithComputed {
  items: string[]
  addItem: (item: string) => void
  // Computed in selector, not stored
}

const useStore = create<StoreWithComputed>()((set) => ({
  items: [],
  addItem: (item) => set((state) => ({ items: [...state.items, item] })),
}))

// Use in component
function ItemCount() {
  const count = useStore((state) => state.items.length)
  return <div>{count} items</div>
}
typescript
interface StoreWithComputed {
  items: string[]
  addItem: (item: string) => void
  // 计算值在选择器中定义,而非存储
}

const useStore = create<StoreWithComputed>()((set) => ({
  items: [],
  addItem: (item) => set((state) => ({ items: [...state.items, item] })),
}))

// 在组件中使用
function ItemCount() {
  const count = useStore((state) => state.items.length)
  return <div>{count} 个项目</div>
}

Pattern: Async Actions

模式:异步动作

typescript
interface AsyncStore {
  data: string | null
  isLoading: boolean
  error: string | null
  fetchData: () => Promise<void>
}

const useAsyncStore = create<AsyncStore>()((set) => ({
  data: null,
  isLoading: false,
  error: null,
  fetchData: async () => {
    set({ isLoading: true, error: null })
    try {
      const response = await fetch('/api/data')
      const data = await response.text()
      set({ data, isLoading: false })
    } catch (error) {
      set({ error: (error as Error).message, isLoading: false })
    }
  },
}))
typescript
interface AsyncStore {
  data: string | null
  isLoading: boolean
  error: string | null
  fetchData: () => Promise<void>
}

const useAsyncStore = create<AsyncStore>()((set) => ({
  data: null,
  isLoading: false,
  error: null,
  fetchData: async () => {
    set({ isLoading: true, error: null })
    try {
      const response = await fetch('/api/data')
      const data = await response.text()
      set({ data, isLoading: false })
    } catch (error) {
      set({ error: (error as Error).message, isLoading: false })
    }
  },
}))

Pattern: Resetting Store

模式:重置Store

typescript
interface ResettableStore {
  count: number
  name: string
  increment: () => void
  reset: () => void
}

const initialState = {
  count: 0,
  name: '',
}

const useStore = create<ResettableStore>()((set) => ({
  ...initialState,
  increment: () => set((state) => ({ count: state.count + 1 })),
  reset: () => set(initialState),
}))
typescript
interface ResettableStore {
  count: number
  name: string
  increment: () => void
  reset: () => void
}

const initialState = {
  count: 0,
  name: '',
}

const useStore = create<ResettableStore>()((set) => ({
  ...initialState,
  increment: () => set((state) => ({ count: state.count + 1 })),
  reset: () => set(initialState),
}))

Pattern: Selector with Params

模式:带参数的选择器

typescript
interface TodoStore {
  todos: Array<{ id: string; text: string; done: boolean }>
  addTodo: (text: string) => void
  toggleTodo: (id: string) => void
}

const useStore = create<TodoStore>()((set) => ({
  todos: [],
  addTodo: (text) =>
    set((state) => ({
      todos: [...state.todos, { id: Date.now().toString(), text, done: false }],
    })),
  toggleTodo: (id) =>
    set((state) => ({
      todos: state.todos.map((todo) =>
        todo.id === id ? { ...todo, done: !todo.done } : todo
      ),
    })),
}))

// Use with parameter
function Todo({ id }: { id: string }) {
  const todo = useStore((state) => state.todos.find((t) => t.id === id))
  const toggleTodo = useStore((state) => state.toggleTodo)

  if (!todo) return null

  return (
    <div>
      <input
        type="checkbox"
        checked={todo.done}
        onChange={() => toggleTodo(id)}
      />
      {todo.text}
    </div>
  )
}

typescript
interface TodoStore {
  todos: Array<{ id: string; text: string; done: boolean }>
  addTodo: (text: string) => void
  toggleTodo: (id: string) => void
}

const useStore = create<TodoStore>()((set) => ({
  todos: [],
  addTodo: (text) =>
    set((state) => ({
      todos: [...state.todos, { id: Date.now().toString(), text, done: false }],
    })),
  toggleTodo: (id) =>
    set((state) => ({
      todos: state.todos.map((todo) =>
        todo.id === id ? { ...todo, done: !todo.done } : todo
      ),
    })),
}))

// 带参数使用
function Todo({ id }: { id: string }) {
  const todo = useStore((state) => state.todos.find((t) => t.id === id))
  const toggleTodo = useStore((state) => state.toggleTodo)

  if (!todo) return null

  return (
    <div>
      <input
        type="checkbox"
        checked={todo.done}
        onChange={() => toggleTodo(id)}
      />
      {todo.text}
    </div>
  )
}

Using Bundled Resources

使用捆绑资源

Templates (templates/)

模板(templates/)

This skill includes 8 ready-to-use template files:
  • basic-store.ts
    - Minimal JavaScript store example
  • typescript-store.ts
    - Properly typed TypeScript store
  • persist-store.ts
    - localStorage persistence with migration
  • slices-pattern.ts
    - Modular store organization
  • devtools-store.ts
    - Redux DevTools integration
  • nextjs-store.ts
    - SSR-safe Next.js store with hydration
  • computed-store.ts
    - Derived state patterns
  • async-actions-store.ts
    - Async operations with loading states
Example Usage:
bash
undefined
本技能包含8个可直接使用的模板文件:
  • basic-store.ts
    - 极简JavaScript Store示例
  • typescript-store.ts
    - 正确类型化的TypeScript Store
  • persist-store.ts
    - 带迁移的localStorage持久化
  • slices-pattern.ts
    - 模块化Store组织
  • devtools-store.ts
    - Redux DevTools集成
  • nextjs-store.ts
    - 支持SSR的Next.js安全Store(带hydration)
  • computed-store.ts
    - 派生状态模式
  • async-actions-store.ts
    - 带加载状态的异步操作
使用示例:
bash
undefined

Copy template to your project

复制模板到你的项目

cp ~/.claude/skills/zustand-state-management/templates/typescript-store.ts src/store/

**When to use each:**
- Use `basic-store.ts` for quick prototypes
- Use `typescript-store.ts` for most production apps
- Use `persist-store.ts` when state needs to survive page reloads
- Use `slices-pattern.ts` for large, complex stores (100+ lines)
- Use `nextjs-store.ts` for Next.js projects with SSR
cp ~/.claude/skills/zustand-state-management/templates/typescript-store.ts src/store/

**各模板适用场景:**
- `basic-store.ts` 用于快速原型开发
- `typescript-store.ts` 用于大多数生产环境应用
- `persist-store.ts` 用于需要跨页面刷新保留的状态
- `slices-pattern.ts` 用于大型复杂Store(100行以上)
- `nextjs-store.ts` 用于带SSR的Next.js项目

References (references/)

参考资料(references/)

Deep-dive documentation for complex scenarios:
  • middleware-guide.md
    - Complete middleware documentation (persist, devtools, immer, custom)
  • typescript-patterns.md
    - Advanced TypeScript patterns and troubleshooting
  • nextjs-hydration.md
    - SSR, hydration, and Next.js best practices
  • migration-guide.md
    - Migrating from Redux, Context API, or Zustand v4
When Claude should load these:
  • Load
    middleware-guide.md
    when user asks about persistence, devtools, or custom middleware
  • Load
    typescript-patterns.md
    when encountering complex type inference issues
  • Load
    nextjs-hydration.md
    for Next.js-specific problems
  • Load
    migration-guide.md
    when migrating from other state management solutions
针对复杂场景的深度文档:
  • middleware-guide.md
    - 完整的中间件文档(持久化、开发者工具、immer、自定义)
  • typescript-patterns.md
    - 进阶TypeScript模式与故障排除
  • nextjs-hydration.md
    - SSR、hydration与Next.js最佳实践
  • migration-guide.md
    - 从Redux、Context API或Zustand v4迁移指南
Claude应何时加载这些资料:
  • 当用户询问持久化、开发者工具或自定义中间件时,加载
    middleware-guide.md
  • 遇到复杂类型推断问题时,加载
    typescript-patterns.md
  • 处理Next.js特定问题时,加载
    nextjs-hydration.md
  • 从其他状态管理方案迁移时,加载
    migration-guide.md

Scripts (scripts/)

脚本(scripts/)

  • check-versions.sh
    - Verify Zustand version and compatibility
Usage:
bash
cd your-project/
~/.claude/skills/zustand-state-management/scripts/check-versions.sh

  • check-versions.sh
    - 验证Zustand版本与兼容性
使用方法:
bash
cd your-project/
~/.claude/skills/zustand-state-management/scripts/check-versions.sh

Advanced Topics

进阶主题

Vanilla Store (Without React)

Vanilla Store(不依赖React)

typescript
import { createStore } from 'zustand/vanilla'

const store = createStore<CounterStore>()((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))

// Subscribe to changes
const unsubscribe = store.subscribe((state) => {
  console.log('Count changed:', state.count)
})

// Get current state
console.log(store.getState().count)

// Update state
store.getState().increment()

// Cleanup
unsubscribe()
typescript
import { createStore } from 'zustand/vanilla'

const store = createStore<CounterStore>()((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))

// 订阅变化
const unsubscribe = store.subscribe((state) => {
  console.log('计数变化:', state.count)
})

// 获取当前状态
console.log(store.getState().count)

// 更新状态
store.getState().increment()

// 清理
unsubscribe()

Custom Middleware

自定义中间件

typescript
import { StateCreator, StoreMutatorIdentifier } from 'zustand'

type Logger = <T>(
  f: StateCreator<T, [], []>,
  name?: string,
) => StateCreator<T, [], []>

const logger: Logger = (f, name) => (set, get, store) => {
  const loggedSet: typeof set = (...a) => {
    set(...(a as Parameters<typeof set>))
    console.log(`[${name}]:`, get())
  }
  return f(loggedSet, get, store)
}

// Use custom middleware
const useStore = create<MyStore>()(
  logger((set) => ({
    // store definition
  }), 'MyStore'),
)
typescript
import { StateCreator, StoreMutatorIdentifier } from 'zustand'

type Logger = <T>(
  f: StateCreator<T, [], []>,
  name?: string,
) => StateCreator<T, [], []>

const logger: Logger = (f, name) => (set, get, store) => {
  const loggedSet: typeof set = (...a) => {
    set(...(a as Parameters<typeof set>))
    console.log(`[${name}]:`, get())
  }
  return f(loggedSet, get, store)
}

// 使用自定义中间件
const useStore = create<MyStore>()(
  logger((set) => ({
    // store定义
  }), 'MyStore'),
)

Immer Middleware (Mutable Updates)

Immer中间件(可变更新)

typescript
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'

interface TodoStore {
  todos: Array<{ id: string; text: string }>
  addTodo: (text: string) => void
}

const useStore = create<TodoStore>()(
  immer((set) => ({
    todos: [],
    addTodo: (text) =>
      set((state) => {
        // Mutate directly with Immer
        state.todos.push({ id: Date.now().toString(), text })
      }),
  })),
)

typescript
import { create } from 'zustand'
import { immer } from 'zustand/middleware/immer'

interface TodoStore {
  todos: Array<{ id: string; text: string }>
  addTodo: (text: string) => void
}

const useStore = create<TodoStore>()(
  immer((set) => ({
    todos: [],
    addTodo: (text) =>
      set((state) => {
        // 使用Immer直接修改
        state.todos.push({ id: Date.now().toString(), text })
      }),
  })),
)

Dependencies

依赖项

Required:
  • zustand@5.0.8
    - State management library
  • react@18.0.0+
    - React framework
Optional:
  • @types/node
    - For TypeScript path resolution
  • immer
    - For mutable update syntax
  • Redux DevTools Extension - For devtools middleware

必填:
  • zustand@5.0.8
    - 状态管理库
  • react@18.0.0+
    - React框架
可选:
  • @types/node
    - 用于TypeScript路径解析
  • immer
    - 用于可变更新语法
  • Redux DevTools Extension - 用于开发者工具中间件

Official Documentation

官方文档

Package Versions (Verified 2025-10-24)

包版本(2025-10-24已验证)

json
{
  "dependencies": {
    "zustand": "^5.0.8",
    "react": "^19.0.0"
  },
  "devDependencies": {
    "@types/node": "^22.0.0",
    "typescript": "^5.0.0"
  }
}
Compatibility:
  • React 18+, React 19 ✅
  • TypeScript 5+ ✅
  • Next.js 14+, Next.js 15+ ✅
  • Vite 5+ ✅

json
{
  "dependencies": {
    "zustand": "^5.0.8",
    "react": "^19.0.0"
  },
  "devDependencies": {
    "@types/node": "^22.0.0",
    "typescript": "^5.0.0"
  }
}
兼容性:
  • React 18+, React 19 ✅
  • TypeScript 5+ ✅
  • Next.js 14+, Next.js 15+ ✅
  • Vite 5+ ✅

Troubleshooting

故障排除

Problem: Store updates don't trigger re-renders

问题:Store更新未触发重渲染

Solution: Ensure you're using selector functions, not destructuring:
const bears = useStore(state => state.bears)
not
const { bears } = useStore()
解决方案: 确保使用选择器函数,而非解构:
const bears = useStore(state => state.bears)
而非
const { bears } = useStore()

Problem: TypeScript errors with middleware

问题:使用中间件时出现TypeScript错误

Solution: Use double parentheses:
create<T>()()
not
create<T>()
解决方案: 使用双括号:
create<T>()()
而非
create<T>()

Problem: Persist middleware causes hydration error

问题:持久化中间件导致hydration错误

Solution: Implement
_hasHydrated
flag pattern (see Issue #1)
解决方案: 实现
_hasHydrated
标志模式(见问题#1)

Problem: Actions not showing in Redux DevTools

问题:动作未显示在Redux DevTools中

Solution: Pass action name as third parameter to
set
:
set(newState, undefined, 'actionName')
解决方案: 将动作名称作为第三个参数传递给
set
set(newState, undefined, 'actionName')

Problem: Store state resets unexpectedly

问题:Store状态意外重置

Solution: Check if using HMR (hot module replacement) - Zustand resets on module reload in development

解决方案: 检查是否使用了HMR(热模块替换)- 在开发环境中,Zustand会在模块重载时重置

Complete Setup Checklist

完整设置检查清单

Use this checklist to verify your Zustand setup:
  • Installed
    zustand@5.0.8
    or later
  • Created store with proper TypeScript types
  • Used
    create<T>()()
    double parentheses syntax
  • Tested selector functions in components
  • Verified components only re-render when selected state changes
  • If using persist: Configured unique storage name
  • If using persist: Implemented hydration check for Next.js
  • If using devtools: Named actions for debugging
  • If using slices: Properly typed
    StateCreator
    for each slice
  • All actions are pure functions
  • No direct state mutations
  • Store works in production build

Questions? Issues?
  1. Check references/typescript-patterns.md for TypeScript help
  2. Check references/nextjs-hydration.md for Next.js issues
  3. Check references/middleware-guide.md for persist/devtools help
  4. Official docs: https://zustand.docs.pmnd.rs/
  5. GitHub issues: https://github.com/pmndrs/zustand/issues
使用此清单验证你的Zustand设置:
  • 已安装
    zustand@5.0.8
    或更高版本
  • 使用正确的TypeScript类型创建了Store
  • 使用了
    create<T>()()
    双括号语法
  • 在组件中测试了选择器函数
  • 验证组件仅在选中状态变化时才重渲染
  • 如果使用持久化:配置了唯一的存储名称
  • 如果使用持久化:为Next.js实现了hydration检查
  • 如果使用开发者工具:为调试命名了动作
  • 如果使用切片:为每个切片正确类型化了
    StateCreator
  • 所有动作都是纯函数
  • 无直接状态修改
  • Store在生产构建中正常工作

有疑问?遇到问题?
  1. 查看references/typescript-patterns.md获取TypeScript相关帮助
  2. 查看references/nextjs-hydration.md获取Next.js相关问题帮助
  3. 查看references/middleware-guide.md获取持久化/开发者工具相关帮助
  4. 官方文档:https://zustand.docs.pmnd.rs/
  5. GitHub问题:https://github.com/pmndrs/zustand/issues