项目基础准备之Zustand:轻量级 React 状态管理的优雅之选

0 阅读5分钟

Zustand:轻量级 React 状态管理的优雅之选

在 React 生态系统中,状态管理一直是一个核心话题。从早期的 Redux 到后来的 MobX、Recoil,再到如今的 Jotai 和 Zustand,开发者们一直在寻找更简洁、高效且易于维护的解决方案。其中,Zustand 凭借其极简的 API、出色的性能和零依赖的特性,迅速成为许多开发者的首选。

本文将深入探讨 Zustand 的核心概念、使用场景、最佳实践,并通过实际代码示例展示如何将其集成到你的 React 项目中。


什么是 Zustand?

Zustand 是一个小型、快速且可扩展的状态管理库,专为 React 设计。它的名字来源于德语“状态”(Zustand = state),寓意清晰明了。与 Redux 不同,Zustand 不需要复杂的样板代码(如 action creators、reducers 或 provider 包裹),也不需要额外的上下文包装器(Context Provider)。它基于 Hooks 构建,但又不完全依赖它们,因此可以在组件外部直接使用。

核心特点

  • 极简 API:只需几行代码即可创建全局状态。
  • 无依赖:不依赖 React Context 或其他外部库。
  • 高性能:采用细粒度订阅机制,避免不必要的重渲染。
  • TypeScript 友好:原生支持类型推断。
  • 中间件支持:内置持久化、日志记录、调试等中间件。
  • 服务端渲染(SSR)兼容:适用于 Next.js 等框架。

安装与基础用法

安装

npm install zustand
# 或
yarn add zustand

创建一个简单的 Store

// store.ts
import { create } from 'zustand';

interface BearState {
  bears: number;
  increase: () => void;
  decrease: () => void;
}

export const useBearStore = create<BearState>((set) => ({
  bears: 0,
  increase: () => set((state) => ({ bears: state.bears + 1 })),
  decrease: () => set((state) => ({ bears: state.bears - 1 })),
}));

在组件中使用

// BearCounter.tsx
import React from 'react';
import { useBearStore } from './store';

const BearCounter: React.FC = () => {
  const { bears, increase, decrease } = useBearStore();

  return (
    <div>
      <h2>🐻 Bears: {bears}</h2>
      <button onClick={increase}>+1</button>
      <button onClick={decrease}>-1</button>
    </div>
  );
};

export default BearCounter;

可以看到,整个流程非常直观:定义状态结构 → 创建 store → 在组件中调用 hook 获取状态和方法。


高级功能详解

1. 选择器优化(避免多余重渲染)

Zustand 允许你通过选择器(selector)只订阅需要的部分状态,从而提升性能:

const bearCount = useBearStore((state) => state.bears);

这样即使 store 中其他字段变化,也不会触发该组件重新渲染。

2. 持久化状态(Persist Middleware)

Zustand 提供了内置的 persist 中间件,可轻松将状态保存到 localStorage 或自定义存储引擎:

import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';

interface TodoState {
  todos: string[];
  addTodo: (todo: string) => void;
}

export const useTodoStore = create<TodoState>()(
  persist(
    (set) => ({
      todos: [],
      addTodo: (todo) => set((state) => ({ todos: [...state.todos, todo] })),
    }),
    {
      name: 'todo-storage', // localStorage key
      storage: createJSONStorage(() => localStorage),
    }
  )
);

刷新页面后,待办事项依然存在!

3. 异步操作

Zustand 天然支持 async/await,无需特殊处理:

interface UserState {
  user: { name: string; age: number } | null;
  fetchUser: () => Promise<void>;
}

export const useUserStore = create<UserState>((set) => ({
  user: null,
  fetchUser: async () => {
    const res = await fetch('/api/user');
    const data = await res.json();
    set({ user: data });
  },
}));

在组件中调用:

const { user, fetchUser } = useUserStore();

useEffect(() => {
  fetchUser();
}, []);

4. 多 Store 组合

虽然 Zustand 鼓励单一 store,但你也可以根据业务模块拆分多个 store,并在需要时组合使用:

const useAuthStore = create(...);
const useCartStore = create(...);

// 在组件中同时使用
const { user } = useAuthStore();
const { items } = useCartStore();

与其他状态管理方案对比

特性ZustandRedux ToolkitJotaiRecoil
学习曲线⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
样板代码极少较多中等
性能
TypeScript 支持优秀良好优秀良好
持久化内置中间件需额外配置需第三方需第三方
SSR 支持⚠️ 有限支持
社区活跃度极高中高

💡 总结:如果你追求简单、高效且不想被复杂架构束缚,Zustand 是理想选择;若项目极其庞大且需要严格的状态追踪,Redux 仍有一席之地。


最佳实践建议

  1. 按功能划分 Store
    不要把所有状态塞进一个巨大的 store。例如:useAuthStoreuseProductStoreuseUIStore
  2. 善用选择器
    始终使用选择器提取所需数据,防止无关更新导致性能下降。
  3. 利用中间件增强能力
    除了 persist,还有 devtools(连接 Redux DevTools)、immer(不可变更新语法糖)等实用中间件。
  4. 测试友好
    Zustand 的 store 是纯函数,易于单元测试。你可以直接导入 store 并模拟操作。
  5. 避免过度抽象
    Zustand 的优势在于简洁,不要为了“统一”而强行封装成复杂的类或工厂函数。

实际案例:电商购物车系统

下面是一个简化版的购物车实现:

// cartStore.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

export interface CartItem {
  id: number;
  name: string;
  price: number;
  quantity: number;
}

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

export const useCartStore = create<CartState>()(
  persist(
    (set, get) => ({
      items: [],
      addItem: (item) =>
        set((state) => {
          const existing = state.items.find((i) => i.id === item.id);
          if (existing) {
            return {
              items: state.items.map((i) =>
                i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i
              ),
            };
          }
          return { items: [...state.items, { ...item, quantity: 1 }] };
        }),
      removeItem: (id) =>
        set((state) => ({
          items: state.items.filter((i) => i.id !== id),
        })),
      updateQuantity: (id, quantity) =>
        set((state) => ({
          items: state.items.map((i) =>
            i.id === id ? { ...i, quantity: Math.max(1, quantity) } : i
          ),
        })),
      clearCart: () => set({ items: [] }),
      total: () =>
        get().items.reduce((sum, item) => sum + item.price * item.quantity, 0),
    }),
    { name: 'cart-storage' }
  )
);

在结账页面中使用:

const { items, total, clearCart } = useCartStore();

return (
  <div>
    <h3>购物车总计:¥{total().toFixed(2)}</h3>
    <button onClick={clearCart}>清空购物车</button>
    {/* 渲染商品列表 */}
  </div>
);

结语

Zustand 代表了现代 React 状态管理的一种趋势:回归本质,拒绝冗余。它没有试图解决所有问题,而是专注于提供一个干净、灵活且强大的基础工具,让开发者能够自由构建适合自己的状态架构。

无论是小型个人项目还是大型企业应用,Zustand 都能胜任。它的低门槛和高上限使其成为当今 React 开发者不可或缺的工具之一。

如果你尚未尝试过 Zustand,现在就是最好的时机。打开终端,输入:

npm install zustand

然后开始你的轻量级状态管理之旅吧!