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:只需学习1个函数(`create`)
- 无样板代码:无需Provider、reducer或actions
- 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} around here...</h1>
}

function Controls() {
  const increase = useBearStore((state) => state.increase)
  return <button onClick={() => increase(1)}>Add bear</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 }))
✅ 为persist中间件的存储键使用唯一名称 ✅ 使用
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"
来源
问题原因: Persist中间件在客户端读取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:Persist中间件导入错误

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
}

// 为每个切片创建带正确类型的StateCreator
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)

Persist中间件(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)

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中显示persist动作。

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`
- 大型复杂Store(100行以上)使用`slices-pattern.ts`
- Next.js项目使用`nextjs-store.ts`

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
    - 完整的中间件文档(persist、devtools、immer、自定义)
  • typescript-patterns.md
    - 高级TypeScript模式和故障排除
  • nextjs-hydration.md
    - SSR、hydration和Next.js最佳实践
  • migration-guide.md
    - 从Redux、Context API或Zustand v4迁移
Claude加载时机
  • 用户询问持久化、devtools或自定义中间件时加载
    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('Count changed:', 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 - devtools中间件使用

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

问题:Persist中间件导致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>()()
    双括号语法
  • 在组件中测试了选择器函数
  • 验证组件仅在选中状态变化时重渲染
  • 如果使用persist:配置了唯一的存储名称
  • 如果使用persist:为Next.js实现了hydration检查
  • 如果使用devtools:为动作命名以便调试
  • 如果使用切片:为每个切片正确类型化
    StateCreator
  • 所有动作都是纯函数
  • 无直接状态修改
  • Store在生产构建中正常工作

有疑问?遇到问题?
  1. 查看references/typescript-patterns.md获取TypeScript帮助
  2. 查看references/nextjs-hydration.md获取Next.js相关问题解决方案
  3. 查看references/middleware-guide.md获取persist/devtools帮助
  4. 官方文档:https://zustand.docs.pmnd.rs/
  5. GitHub问题:https://github.com/pmndrs/zustand/issues