zustand-state-management
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseZustand 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 zustandbash
npm install zustandor
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 moreyarn 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 - this is required for TypeScript with middleware.
create<T>()()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 }),
}))关键注意事项:注意这里的双括号 - 这是TypeScript环境下使用中间件的必需语法。
create<T>()()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 syntax (currying for middleware)
create<T>()() - 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 (double parentheses) in TypeScript for middleware compatibility
✅ Define separate interfaces for state and actions
✅ Use selector functions to extract specific state slices
✅ Use with updater functions for derived state:
✅ Use unique names for persist middleware storage keys
✅ Handle Next.js hydration with flag pattern
✅ Use for selecting multiple values
✅ Keep actions pure (no side effects except state updates)
create<T>()()setset((state) => ({ count: state.count + 1 }))hasHydratedshallow✅ 在TypeScript中使用(双括号)以兼容中间件
✅ 为状态和动作单独定义接口
✅ 使用选择器函数提取特定状态切片
✅ 对于派生状态,使用带更新器函数的:
✅ 为persist中间件的存储键使用唯一名称
✅ 使用标志模式处理Next.js hydration
✅ 选择多个值时使用
✅ 保持动作纯函数(除状态更新外无副作用)
create<T>()()setset((state) => ({ count: state.count + 1 }))hasHydratedshallowNever Do
严禁操作
❌ Use (single parentheses) in TypeScript - breaks middleware types
❌ Mutate state directly: - use immutable updates
❌ Create new objects in selectors: - 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
create<T>(...)set((state) => { state.count++; return state })useStore((state) => ({ a: state.a }))❌ 在TypeScript中使用(单括号)- 会破坏中间件类型
❌ 直接修改状态: - 使用不可变更新
❌ 在选择器中创建新对象: - 会导致无限渲染
❌ 多个Store使用相同的存储名称 - 会导致数据冲突
❌ 在SSR期间未进行hydration检查就访问localStorage
❌ 使用Zustand管理服务端状态 - 改用TanStack Query
❌ 直接导出Store实例 - 始终导出Hook
create<T>(...)set((state) => { state.count++; return state })useStore((state) => ({ a: state.a }))Known Issues Prevention
已知问题预防
This skill prevents 5 documented issues:
该技能可预防5个已记录的问题:
Issue #1: Next.js Hydration Mismatch
问题1:Next.js Hydration不匹配
Error: or
"Text content does not match server-rendered HTML""Hydration failed"Source:
- DEV Community: Persist middleware in Next.js
- GitHub Discussions #2839
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"来源:
- DEV Community: Persist middleware in Next.js
- GitHub Discussions #2839
问题原因:
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, types break with middleware
StateCreatorWhy It Happens:
The currying syntax is required for middleware to work with TypeScript inference.
create<T>()()Prevention:
typescript
// ❌ WRONG - Single parentheses
const useStore = create<MyStore>((set) => ({
// ...
}))
// ✅ CORRECT - Double parentheses
const useStore = create<MyStore>()((set) => ({
// ...
}))Rule: Always use in TypeScript, even without middleware (future-proof).
create<T>()()错误信息:类型推断失败,使用中间件时类型失效
StateCreator问题原因:
柯里化语法是中间件与TypeScript推断兼容的必需条件。
create<T>()()解决方案:
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: types fail to infer, complex middleware types break
StateCreatorSource: Official Slices Pattern Guide
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: shows persist actions in DevTools.
devtools(persist(...))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:
- - Minimal JavaScript store example
basic-store.ts - - Properly typed TypeScript store
typescript-store.ts - - localStorage persistence with migration
persist-store.ts - - Modular store organization
slices-pattern.ts - - Redux DevTools integration
devtools-store.ts - - SSR-safe Next.js store with hydration
nextjs-store.ts - - Derived state patterns
computed-store.ts - - Async operations with loading states
async-actions-store.ts
Example Usage:
bash
undefined该技能包含8个可直接使用的模板文件:
- - 极简JavaScript Store示例
basic-store.ts - - 正确类型化的TypeScript Store
typescript-store.ts - - 带迁移的localStorage持久化
persist-store.ts - - 模块化Store组织
slices-pattern.ts - - Redux DevTools集成
devtools-store.ts - - 支持SSR的Next.js安全Store(带hydration)
nextjs-store.ts - - 派生状态模式
computed-store.ts - - 带加载状态的异步操作
async-actions-store.ts
使用示例:
bash
undefinedCopy 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 SSRcp ~/.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:
- - Complete middleware documentation (persist, devtools, immer, custom)
middleware-guide.md - - Advanced TypeScript patterns and troubleshooting
typescript-patterns.md - - SSR, hydration, and Next.js best practices
nextjs-hydration.md - - Migrating from Redux, Context API, or Zustand v4
migration-guide.md
When Claude should load these:
- Load when user asks about persistence, devtools, or custom middleware
middleware-guide.md - Load when encountering complex type inference issues
typescript-patterns.md - Load for Next.js-specific problems
nextjs-hydration.md - Load when migrating from other state management solutions
migration-guide.md
复杂场景的深度文档:
- - 完整的中间件文档(persist、devtools、immer、自定义)
middleware-guide.md - - 高级TypeScript模式和故障排除
typescript-patterns.md - - SSR、hydration和Next.js最佳实践
nextjs-hydration.md - - 从Redux、Context API或Zustand v4迁移
migration-guide.md
Claude加载时机:
- 用户询问持久化、devtools或自定义中间件时加载
middleware-guide.md - 遇到复杂类型推断问题时加载
typescript-patterns.md - 处理Next.js特定问题时加载
nextjs-hydration.md - 从其他状态管理方案迁移时加载
migration-guide.md
Scripts (scripts/)
脚本(scripts/)
- - Verify Zustand version and compatibility
check-versions.sh
Usage:
bash
cd your-project/
~/.claude/skills/zustand-state-management/scripts/check-versions.sh- - 验证Zustand版本和兼容性
check-versions.sh
使用方法:
bash
cd your-project/
~/.claude/skills/zustand-state-management/scripts/check-versions.shAdvanced 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:
- - State management library
zustand@5.0.8 - - React framework
react@18.0.0+
Optional:
- - For TypeScript path resolution
@types/node - - For mutable update syntax
immer - Redux DevTools Extension - For devtools middleware
必需:
- - 状态管理库
zustand@5.0.8 - - React框架
react@18.0.0+
可选:
- - TypeScript路径解析
@types/node - - 可变更新语法
immer - Redux DevTools Extension - devtools中间件使用
Official Documentation
官方文档
- Zustand: https://zustand.docs.pmnd.rs/
- GitHub: https://github.com/pmndrs/zustand
- TypeScript Guide: https://zustand.docs.pmnd.rs/guides/typescript
- Slices Pattern: https://github.com/pmndrs/zustand/blob/main/docs/guides/slices-pattern.md
- Context7 Library ID:
/pmndrs/zustand
- Zustand:https://zustand.docs.pmnd.rs/
- GitHub:https://github.com/pmndrs/zustand
- TypeScript指南:https://zustand.docs.pmnd.rs/guides/typescript
- 切片模式:https://github.com/pmndrs/zustand/blob/main/docs/guides/slices-pattern.md
- Context7库ID:
/pmndrs/zustand
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: not
const bears = useStore(state => state.bears)const { bears } = useStore()解决方案:确保使用选择器函数,而非解构: 而非
const bears = useStore(state => state.bears)const { bears } = useStore()Problem: TypeScript errors with middleware
问题:中间件出现TypeScript错误
Solution: Use double parentheses: not
create<T>()()create<T>()解决方案:使用双括号: 而非
create<T>()()create<T>()Problem: Persist middleware causes hydration error
问题:Persist中间件导致hydration错误
Solution: Implement flag pattern (see Issue #1)
_hasHydrated解决方案:实现标志模式(见问题1)
_hasHydratedProblem: Actions not showing in Redux DevTools
问题:动作未显示在Redux DevTools中
Solution: Pass action name as third parameter to :
setset(newState, undefined, 'actionName')解决方案:将动作名称作为的第三个参数传递:
setset(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 or later
zustand@5.0.8 - Created store with proper TypeScript types
- Used double parentheses syntax
create<T>()() - 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 for each slice
StateCreator - All actions are pure functions
- No direct state mutations
- Store works in production build
Questions? Issues?
- Check references/typescript-patterns.md for TypeScript help
- Check references/nextjs-hydration.md for Next.js issues
- Check references/middleware-guide.md for persist/devtools help
- Official docs: https://zustand.docs.pmnd.rs/
- 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在生产构建中正常工作
有疑问?遇到问题?
- 查看references/typescript-patterns.md获取TypeScript帮助
- 查看references/nextjs-hydration.md获取Next.js相关问题解决方案
- 查看references/middleware-guide.md获取persist/devtools帮助
- 官方文档:https://zustand.docs.pmnd.rs/
- GitHub问题:https://github.com/pmndrs/zustand/issues