📚 现代前端开发 目录
阶段3:React
第 17 / 35 课

状态管理:Zustand

简单强大的状态管理

📖 核心概念

💻 代码实现

Zustand Store ✅ typescript
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import { persist, devtools } from 'zustand/middleware';
import { subscribeWithSelector } from 'zustand/middleware';

// ===== 基础Store =====
interface CartItem {
  id: string;
  name: string;
  price: number;
  quantity: number;
}

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

const useCartStore = create<CartStore>()(
  devtools(
    persist(
      immer((set, get) => ({
        items: [],

        addItem: (item) => set((state) => {
          const existing = state.items.find(i => i.id === item.id);
          if (existing) {
            existing.quantity += 1;
          } else {
            state.items.push({ ...item, quantity: 1 });
          }
        }),

        removeItem: (id) => set((state) => {
          const index = state.items.findIndex(i => i.id === id);
          if (index > -1) state.items.splice(index, 1);
        }),

        updateQuantity: (id, quantity) => set((state) => {
          const item = state.items.find(i => i.id === id);
          if (item) item.quantity = Math.max(0, quantity);
        }),

        clearCart: () => set((state) => { state.items = []; }),

        totalItems: () => get().items.reduce((sum, i) => sum + i.quantity, 0),
        totalPrice: () => get().items.reduce((sum, i) => sum + i.price * i.quantity, 0),
      })),
      { name: 'cart-storage' }
    ),
    { name: 'CartStore' }
  )
);
切片模式与异步 ✅ typescript
// ===== 切片模式:模块化Store =====
// stores/authSlice.ts
interface AuthSlice {
  user: User | null;
  token: string | null;
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
}

const createAuthSlice: StateCreator<RootState, [], [], AuthSlice> = (set) => ({
  user: null,
  token: null,
  login: async (email, password) => {
    const response = await api.login({ email, password });
    set({ user: response.user, token: response.token });
    localStorage.setItem('token', response.token);
  },
  logout: () => {
    set({ user: null, token: null });
    localStorage.removeItem('token');
  },
});

// stores/uiSlice.ts
interface UISlice {
  theme: 'light' | 'dark';
  sidebarOpen: boolean;
  toggleTheme: () => void;
  toggleSidebar: () => void;
}

const createUISlice: StateCreator<RootState, [], [], UISlice> = (set) => ({
  theme: 'dark',
  sidebarOpen: false,
  toggleTheme: () => set((s) => ({ theme: s.theme === 'dark' ? 'light' : 'dark' })),
  toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })),
});

// 合并切片
type RootState = AuthSlice & UISlice;
const useStore = create<RootState>()((...a) => ({
  ...createAuthSlice(...a),
  ...createUISlice(...a),
}));

// ===== 组件中使用 =====
function ShoppingCart() {
  // 选择性订阅:只有items变化时才重渲染
  const items = useCartStore((s) => s.items);
  const totalPrice = useCartStore((s) => s.totalPrice());
  const addItem = useCartStore((s) => s.addItem);

  return (
    <div>
      {items.map(item => (
        <CartItem key={item.id} item={item} />
      ))}
      <div className="total">总计: ¥{totalPrice}</div>
    </div>
  );
}

// 外部订阅(非React组件中使用)
const unsubscribe = useCartStore.subscribe(
  (state) => state.items,
  (items) => { console.log('购物车变化:', items); },
  { equalityFn: (a, b) => a.length === b.length }
);

// ===== 异步操作最佳实践 =====
interface AsyncState<T> {
  data: T | null;
  loading: boolean;
  error: string | null;
}

function createAsyncSlice<T>(key: string, fetcher: () => Promise<T>) {
  return create<AsyncState<T> & { fetch: () => Promise<void> }>((set) => ({
    data: null,
    loading: false,
    error: null,
    fetch: async () => {
      set({ loading: true, error: null });
      try {
        const data = await fetcher();
        set({ data, loading: false });
      } catch (err) {
        set({ error: (err as Error).message, loading: false });
      }
    },
  }));
}

🎯 练习任务

🏆 成就解锁
状态管理专家 — 掌握Zustand状态管理,构建可预测的应用状态