创建 Store #

基本创建 #

Zustand 使用 create 函数创建 store。这是 Zustand 的核心 API,也是你唯一需要记住的函数。

最简单的 Store #

tsx
import { create } from 'zustand'

const useStore = create((set) => ({
  count: 0,
}))

完整的 Store 结构 #

tsx
import { create } from 'zustand'

interface StoreState {
  // 状态
  count: number
  name: string
  
  // 更新函数
  increment: () => void
  decrement: () => void
  setName: (name: string) => void
  reset: () => void
}

const useStore = create<StoreState>((set) => ({
  // 初始状态
  count: 0,
  name: '',
  
  // 更新函数
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
  setName: (name) => set({ name }),
  reset: () => set({ count: 0, name: '' }),
}))

理解 set 函数 #

set 函数是更新状态的唯一方式。它支持两种调用模式。

直接设置 #

tsx
const useStore = create((set) => ({
  count: 0,
  
  // 直接设置新值
  setCount: (value) => set({ count: value }),
  
  // 设置多个状态
  setMultiple: () => set({ count: 10, name: 'John' }),
}))

基于前一个状态 #

tsx
const useStore = create((set) => ({
  count: 0,
  
  // 基于前一个状态更新
  increment: () => set((state) => ({ count: state.count + 1 })),
  
  // 复杂计算
  doubleAndAdd: (value) => set((state) => ({
    count: state.count * 2 + value
  })),
}))

set 函数的第三个参数 #

set 函数接受第三个参数,用于标识更新来源(调试用):

tsx
const useStore = create((set) => ({
  count: 0,
  
  increment: () => set(
    (state) => ({ count: state.count + 1 }),
    false,  // 是否替换整个状态
    'increment'  // action 名称(用于 devtools)
  ),
}))

理解 get 函数 #

get 函数用于获取当前状态,常用于读取状态进行计算:

tsx
const useStore = create((set, get) => ({
  count: 0,
  
  increment: () => set((state) => ({ count: state.count + 1 })),
  
  // 使用 get 获取当前状态
  logCurrentCount: () => {
    console.log('Current count:', get().count)
  },
  
  // 在异步操作中使用
  asyncIncrement: async () => {
    const currentCount = get().count
    await someAsyncOperation()
    set({ count: currentCount + 1 })
  },
}))

状态类型定义 #

基本类型 #

tsx
interface State {
  count: number
  name: string
  isActive: boolean
  tags: string[]
}

const useStore = create<State>((set) => ({
  count: 0,
  name: '',
  isActive: false,
  tags: [],
}))

对象类型 #

tsx
interface User {
  id: string
  name: string
  email: string
}

interface State {
  user: User | null
  settings: {
    theme: 'light' | 'dark'
    language: string
  }
}

const useStore = create<State>((set) => ({
  user: null,
  settings: {
    theme: 'light',
    language: 'zh-CN',
  },
  
  updateUser: (user: User) => set({ user }),
  
  updateTheme: (theme: 'light' | 'dark') => 
    set((state) => ({
      settings: { ...state.settings, theme }
    })),
}))

复杂嵌套类型 #

tsx
interface Todo {
  id: string
  text: string
  completed: boolean
}

interface TodoState {
  todos: Todo[]
  filter: 'all' | 'active' | 'completed'
  
  addTodo: (text: string) => void
  toggleTodo: (id: string) => void
  removeTodo: (id: string) => void
  setFilter: (filter: TodoState['filter']) => void
}

const useTodoStore = create<TodoState>((set) => ({
  todos: [],
  filter: 'all',
  
  addTodo: (text) => set((state) => ({
    todos: [
      ...state.todos,
      { id: Date.now().toString(), text, completed: false }
    ]
  })),
  
  toggleTodo: (id) => set((state) => ({
    todos: state.todos.map((todo) =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    )
  })),
  
  removeTodo: (id) => set((state) => ({
    todos: state.todos.filter((todo) => todo.id !== id)
  })),
  
  setFilter: (filter) => set({ filter }),
}))

创建模式 #

模式一:内联定义 #

最简单直接的方式:

tsx
const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))

模式二:分离定义 #

将状态和逻辑分离:

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

const initialState = {
  count: 0,
}

const storeActions = (set: any, get: any) => ({
  increment: () => set((state: State) => ({ count: state.count + 1 })),
  getCount: () => get().count,
})

const useStore = create<State>((set, get) => ({
  ...initialState,
  ...storeActions(set, get),
}))

模式三:类风格 #

使用类来组织 store:

tsx
interface State {
  count: number
  increment: () => void
  decrement: () => void
}

class CounterStore {
  private set: any
  private get: any
  
  constructor(set: any, get: any) {
    this.set = set
    this.get = get
  }
  
  get initialState() {
    return { count: 0 }
  }
  
  get actions() {
    return {
      increment: this.increment,
      decrement: this.decrement,
    }
  }
  
  private increment = () => {
    this.set((state: State) => ({ count: state.count + 1 }))
  }
  
  private decrement = () => {
    this.set((state: State) => ({ count: state.count - 1 }))
  }
}

const useStore = create<State>((set, get) => {
  const store = new CounterStore(set, get)
  return {
    ...store.initialState,
    ...store.actions,
  }
})

实际案例 #

用户认证 Store #

tsx
interface User {
  id: string
  name: string
  email: string
  role: 'admin' | 'user'
}

interface AuthState {
  user: User | null
  token: string | null
  isAuthenticated: boolean
  isLoading: boolean
  error: string | null
  
  login: (email: string, password: string) => Promise<void>
  logout: () => void
  clearError: () => void
}

const useAuthStore = create<AuthState>((set, get) => ({
  user: null,
  token: null,
  isAuthenticated: false,
  isLoading: false,
  error: null,
  
  login: async (email, password) => {
    set({ isLoading: true, error: null })
    
    try {
      const response = await fetch('/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password }),
      })
      
      if (!response.ok) {
        throw new Error('登录失败')
      }
      
      const data = await response.json()
      
      set({
        user: data.user,
        token: data.token,
        isAuthenticated: true,
        isLoading: false,
      })
    } catch (error) {
      set({
        error: error instanceof Error ? error.message : '登录失败',
        isLoading: false,
      })
    }
  },
  
  logout: () => {
    set({
      user: null,
      token: null,
      isAuthenticated: false,
      error: null,
    })
  },
  
  clearError: () => set({ error: null }),
}))

购物车 Store #

tsx
interface CartItem {
  id: string
  productId: string
  name: string
  price: number
  quantity: number
}

interface CartState {
  items: CartItem[]
  totalItems: number
  totalPrice: number
  
  addItem: (item: Omit<CartItem, 'id'>) => void
  removeItem: (id: string) => void
  updateQuantity: (id: string, quantity: number) => void
  clearCart: () => void
}

const useCartStore = create<CartState>((set, get) => ({
  items: [],
  totalItems: 0,
  totalPrice: 0,
  
  addItem: (item) => set((state) => {
    const existingItem = state.items.find(i => i.productId === item.productId)
    
    let newItems: CartItem[]
    if (existingItem) {
      newItems = state.items.map(i =>
        i.productId === item.productId
          ? { ...i, quantity: i.quantity + item.quantity }
          : i
      )
    } else {
      newItems = [...state.items, { ...item, id: Date.now().toString() }]
    }
    
    return {
      items: newItems,
      totalItems: newItems.reduce((sum, i) => sum + i.quantity, 0),
      totalPrice: newItems.reduce((sum, i) => sum + i.price * i.quantity, 0),
    }
  }),
  
  removeItem: (id) => set((state) => {
    const newItems = state.items.filter(i => i.id !== id)
    return {
      items: newItems,
      totalItems: newItems.reduce((sum, i) => sum + i.quantity, 0),
      totalPrice: newItems.reduce((sum, i) => sum + i.price * i.quantity, 0),
    }
  }),
  
  updateQuantity: (id, quantity) => set((state) => {
    if (quantity <= 0) {
      return get().removeItem(id)
    }
    
    const newItems = state.items.map(i =>
      i.id === id ? { ...i, quantity } : i
    )
    
    return {
      items: newItems,
      totalItems: newItems.reduce((sum, i) => sum + i.quantity, 0),
      totalPrice: newItems.reduce((sum, i) => sum + i.price * i.quantity, 0),
    }
  }),
  
  clearCart: () => set({
    items: [],
    totalItems: 0,
    totalPrice: 0,
  }),
}))

最佳实践 #

1. 保持 Store 单一职责 #

tsx
// ✅ 好的做法:每个 store 负责一个领域
const useUserStore = create((set) => ({ /* 用户相关 */ }))
const useCartStore = create((set) => ({ /* 购物车相关 */ }))
const useThemeStore = create((set) => ({ /* 主题相关 */ }))

// ❌ 不推荐:一个 store 管理所有状态
const useAppStore = create((set) => ({
  user: {},
  cart: {},
  theme: {},
  // ...太多职责
}))

2. 使用 TypeScript 类型 #

tsx
// ✅ 始终定义类型
interface State {
  count: number
  increment: () => void
}

const useStore = create<State>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}))

3. 命名规范 #

tsx
// ✅ 好的命名
const useUserStore = create((set) => ({
  user: null,
  setUser: (user) => set({ user }),
  clearUser: () => set({ user: null }),
}))

// ❌ 不好的命名
const useStore = create((set) => ({
  data: null,
  update: (d) => set({ data: d }),
}))

总结 #

创建 Store 是使用 Zustand 的第一步,关键点:

  • 使用 create 函数创建 store
  • 使用 set 函数更新状态
  • 使用 get 函数读取当前状态
  • 定义清晰的 TypeScript 类型
  • 保持 store 的单一职责

接下来,让我们学习 使用 Store,掌握在组件中使用 store 的各种技巧。

最后更新:2026-03-28