Zustand:轻量、简单且强大的React状态管理库

126 阅读3分钟

引言

在React生态系统中,状态管理一直是一个热门话题。从最初的React Context到Redux,再到后来的MobX、Recoil等,开发者们一直在寻找更高效、更简洁的状态管理方案。今天我要介绍的Zustand(德语中意为"状态")就是一个近年来备受关注的轻量级状态管理解决方案。

什么是Zustand?

Zustand是一个小型、快速且可扩展的React状态管理库,由Poimandres团队开发。它的核心理念是提供一个简单直接的API来管理应用状态,同时保持优秀的性能和开发者体验。

image.png

与Redux等传统方案相比,Zustand具有以下特点:

  • 极简API,学习曲线平缓
  • 不需要繁琐的Provider包裹
  • 自动处理依赖跟踪和优化渲染
  • 支持中间件扩展
  • 体积小巧(约1kB)

基本用法

安装

npm install zustand
# 或
yarn add zustand

创建store(核心用法)

import { create } from 'zustand'

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

这一步是Zustand的核心用法,后文会对这里的书写进行详细说明

在组件中使用

function Counter() {
  const { count, increment, decrement, reset } = useStore();
  
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}


Zustand的核心,create的书写

在上面的部分中,最重要的就是书写Zustand的create部分了,在 Zustand 中,create 函数的回调函数是定义 store 的核心部分,它决定了 store 的初始状态和状态更新方法。这个回调函数的写法非常灵活,但通常遵循一定的模式。下面我会详细解释如何编写这个回调函数,并提供不同场景的示例。

1. 回调函数的基本结构

create 的回调函数接收两个主要参数:

  • set: 用于更新状态(必须)。
  • get: 用于读取当前状态(可选)。
import { create } from 'zustand';

const useStore = create((set, get) => ({
  // 初始状态
  count: 0,
  // 更新状态的方法
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

2. 如何编写回调函数

(1) 定义初始状态

在返回的对象中直接声明初始值:

const useStore = create(() => ({
  count: 0,      // 初始状态
  name: "Zustand",
}));

⚠️ 如果这样写,状态将无法更新(因为没有 set),所以通常不推荐。

(2) 使用 set 更新状态

set 有两种用法:

方式 1:直接传入新状态

const useStore = create((set) => ({
  count: 0,
  reset: () => set({ count: 0 }),  // 直接替换为 { count: 0 }
}));

方式 2:基于当前状态计算新状态

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),  // 依赖当前 state
}));

(3) 使用 get 读取当前状态

如果需要在方法中获取最新状态(而不是依赖闭包中的 state),可以用 get

const useStore = create((set, get) => ({
  count: 0,
  logCount: () => {
    const currentCount = get().count;  // 读取当前 count
    console.log(currentCount);
  },
}));

(4) 异步更新状态

Zustand 完全支持异步操作:

const useStore = create((set) => ({
  data: null,
  loading: false,
  fetchData: async () => {
    set({ loading: true });
    const response = await fetch('https://api.example.com/data');
    const result = await response.json();
    set({ data: result, loading: false });  // 异步更新
  },
}));

总结一下书写create回调函数的重要规则

重要规则

  1. set 必须声明:即使你不用它,Zustand 也要求回调函数的第一个参数是 set
  2. 状态不可变:每次更新必须返回新对象(Zustand 内部会处理优化)。
  3. get 是可选的:只有需要读取最新状态时才用。


Zustand与Redux的比较

特性ZustandRedux
学习曲线中到高
样板代码极少较多
性能优化自动选择器优化需要手动优化
中间件支持支持
DevTools需要中间件内置支持
包大小~1kB~5kB + react-redux


最佳实践

  1. 按功能拆分store:虽然可以在一个store中管理所有状态,但建议按功能拆分
  2. 合理使用选择器:只订阅组件实际需要的状态部分
  3. 利用中间件:根据需求添加持久化、日志等中间件
  4. 避免过度嵌套:保持状态结构扁平化
  5. 类型安全:在TypeScript项目中充分利用类型推断