教程 zustand tutorial

核心概念:State 与 Actions

在 Zustand 中,状态管理的核心是 Store(存储),它包含了应用的 State(状态)和 Actions(动作)。理解这些核心概念是掌握 Zustand 的关键。

State:应用的数据源

State 是应用的数据容器,它存储了应用的所有状态信息。在 Zustand 中,State 可以是任何 JavaScript 类型,包括对象、数组、字符串、数字等。

javascript
// 简单的状态
const useStore = create(() => ({
  count: 0,
  name: 'Zustand',
  isLoading: false,
  items: [],
}))

Actions:修改状态的方法

Actions 是修改 State 的函数。在 Zustand 中,Actions 直接定义在 Store 内部,与 State 共存。

javascript
const useStore = create((set) => ({
  // State
  count: 0,
  
  // Actions
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
  setName: (name) => set({ name }),
  setLoading: (isLoading) => set({ isLoading }),
}))

Store:状态与动作的集合

Store 是 Zustand 的核心,它将 State 和 Actions 组织在一起。创建 Store 使用 create 函数,它接受一个函数作为参数,该函数返回 Store 的初始状态和动作。

Store 创建函数的参数

Store 创建函数接收两个参数:

  1. set:用于修改状态的函数
  2. get:用于获取当前状态的函数
javascript
const useStore = create((set, get) => ({
  count: 0,
  
  increment: () => set((state) => ({ count: state.count + 1 })),
  
  // 使用 get 获取当前状态
  incrementTwice: () => {
    const currentCount = get().count
    set({ count: currentCount + 2 })
  },
}))

不可变更新

Zustand 鼓励使用不可变更新模式,这意味着你不应该直接修改状态对象,而是应该创建一个新的状态对象。

错误的做法

javascript
// 不要这样做!
const useStore = create((set) => ({
  user: { name: 'John', age: 30 },
  
  updateAge: (age) => {
    set((state) => {
      state.user.age = age // 直接修改状态对象
      return state
    })
  },
}))

正确的做法

javascript
// 这样做是正确的
const useStore = create((set) => ({
  user: { name: 'John', age: 30 },
  
  updateAge: (age) => {
    set((state) => ({
      user: {
        ...state.user, // 复制现有属性
        age, // 更新年龄
      },
    }))
  },
}))

在组件中使用 State 和 Actions

在 React 组件中,你可以使用自定义 Hook 来访问 Store 中的 State 和 Actions。

访问单个状态

jsx
const count = useStore((state) => state.count)

访问多个状态

jsx
const { count, name } = useStore((state) => ({ 
  count: state.count, 
  name: state.name 
}))

访问 Actions

jsx
const increment = useStore((state) => state.increment)
const { increment, decrement } = useStore((state) => ({ 
  increment: state.increment, 
  decrement: state.decrement 
}))

完整示例

jsx
function Counter() {
  const count = useStore((state) => state.count)
  const { increment, decrement, reset } = useStore((state) => ({
    increment: state.increment,
    decrement: state.decrement,
    reset: state.reset,
  }))

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  )
}

高级状态管理

计算属性

你可以在 Store 中定义计算属性,它们基于其他状态计算得出。

javascript
const useStore = create((set, get) => ({
  todos: [
    { id: 1, text: 'Learn Zustand', completed: true },
    { id: 2, text: 'Build an app', completed: false },
  ],
  
  // 计算属性:完成的任务数量
  completedTodosCount: () => get().todos.filter((todo) => todo.completed).length,
  
  // 计算属性:待完成的任务数量
  pendingTodosCount: () => get().todos.filter((todo) => !todo.completed).length,
}))

在组件中使用计算属性

jsx
function TodoStats() {
  const completedCount = useStore((state) => state.completedTodosCount())
  const pendingCount = useStore((state) => state.pendingTodosCount())

  return (
    <div>
      <p>Completed: {completedCount}</p>
      <p>Pending: {pendingCount}</p>
    </div>
  )
}

State 与 Actions 的最佳实践

1. 将相关的状态和动作组织在一起

javascript
// 好的做法:将计数器相关的状态和动作组织在一起
const useCounterStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}))

2. 保持 Actions 简洁

javascript
// 好的做法:每个 Action 只做一件事
const useUserStore = create((set) => ({
  user: null,
  isLoading: false,
  error: null,
  
  fetchUser: async (id) => {
    set({ isLoading: true, error: null })
    try {
      const response = await fetch(`/api/users/${id}`)
      const user = await response.json()
      set({ user, isLoading: false })
    } catch (error) {
      set({ error: error.message, isLoading: false })
    }
  },
}))

3. 使用选择器避免不必要的重渲染

jsx
// 好的做法:只订阅需要的状态
const count = useStore((state) => state.count)

// 不好的做法:订阅整个 Store
const store = useStore()
const count = store.count

总结

State 和 Actions 是 Zustand 的核心概念:

  • State 是应用的数据源,存储了应用的所有状态信息
  • Actions 是修改 State 的函数,定义在 Store 内部
  • Store 将 State 和 Actions 组织在一起,是 Zustand 的核心
  • 使用不可变更新模式修改状态
  • 使用选择器精确订阅状态,避免不必要的重渲染

理解这些核心概念后,你就可以开始构建更复杂的状态管理逻辑了。在接下来的章节中,我们将学习 性能优化:Selector 与 Shallow,进一步提升你的 Zustand 应用性能。