Zustand Bundle 优化:提升首屏加载速度的动态拆包策略
Zustand Bundle 优化:提升首屏加载速度的动态拆包策略
前言
我是大山哥。
上周帮客户优化状态管理时,前端工程师小赵问我:"大山哥,Zustand 虽然好用,但首屏加载太慢了,怎么优化?"
我打开 Chrome DevTools 一看,状态管理相关的代码打包后竟然有 50KB,而且都是同步加载的。
兄弟,状态管理也要按需加载!
今天,我就来分享如何通过动态拆包策略优化 Zustand 首屏加载速度。
一、问题分析
1.1 当前架构
graph TD A[首屏加载] --> B[加载整个 store] B --> C[store.ts] C --> D[authStore] C --> E[userStore] C --> F[settingsStore] C --> G[cartStore] C --> H[notificationStore] C --> I[themeStore]1.2 问题量化
| Store 模块 | 大小 | 是否首屏必需 |
|---|---|---|
| authStore | 8KB | ✅ 必需 |
| userStore | 12KB | ✅ 必需 |
| settingsStore | 6KB | ❌ 非必需 |
| cartStore | 15KB | ❌ 非必需 |
| notificationStore | 5KB | ❌ 非必需 |
| themeStore | 4KB | ❌ 非必需 |
| 合计 | 50KB | - |
二、动态拆包策略
2.1 按需加载架构
graph TD A[首屏加载] --> B[加载核心 store] B --> C[authStore] B --> D[userStore] E[用户访问购物车] --> F[动态加载 cartStore] G[用户打开设置] --> H[动态加载 settingsStore] I[用户触发通知] --> J[动态加载 notificationStore] K[用户切换主题] --> L[动态加载 themeStore]2.2 核心实现
import { create } from 'zustand'; interface AuthState { isLoggedIn: boolean; token: string | null; login: (token: string) => void; logout: () => void; } interface UserState { user: User | null; setUser: (user: User) => void; clearUser: () => void; } interface CartState { items: CartItem[]; addItem: (item: CartItem) => void; removeItem: (id: string) => void; clearCart: () => void; } // 首屏必需的 store - 同步加载 export const useAuthStore = create<AuthState>((set) => ({ isLoggedIn: false, token: null, login: (token) => set({ isLoggedIn: true, token }), logout: () => set({ isLoggedIn: false, token: null }), })); export const useUserStore = create<UserState>((set) => ({ user: null, setUser: (user) => set({ user }), clearUser: () => set({ user: null }), })); // 非首屏必需的 store - 动态加载 let cartStore: ReturnType<typeof create<CartState>> | null = null; export async function getCartStore(): Promise<ReturnType<typeof create<CartState>>> { if (cartStore) { return cartStore; } // 动态导入 store 实现 const { createCartStore } = await import('./stores/cartStore'); cartStore = createCartStore(); return cartStore; } // Hook 封装 export function useCartStore() { throw new Error('useCartStore should be used with lazy loading'); }2.3 动态 Store 实现
// stores/cartStore.ts import { create } from 'zustand'; import { persist } from 'zustand/middleware'; interface CartItem { id: string; name: string; price: number; quantity: number; } interface CartState { items: CartItem[]; addItem: (item: CartItem) => void; removeItem: (id: string) => void; clearCart: () => void; getItemCount: () => number; getTotalPrice: () => number; } export function createCartStore() { return create<CartState>()( persist( (set, get) => ({ items: [], addItem: (item) => set((state) => ({ items: [...state.items, item], })), removeItem: (id) => set((state) => ({ items: state.items.filter((item) => item.id !== id), })), clearCart: () => set({ items: [] }), getItemCount: () => get().items.reduce((sum, item) => sum + item.quantity, 0), getTotalPrice: () => get().items.reduce((sum, item) => sum + item.price * item.quantity, 0), }), { name: 'cart-storage', } ) ); }三、React 组件集成
3.1 懒加载 Hook
import { useState, useEffect, useCallback } from 'react'; interface UseLazyStoreOptions<T> { loader: () => Promise<T>; onLoad?: (store: T) => void; onError?: (error: Error) => void; } export function useLazyStore<T>(options: UseLazyStoreOptions<T>): { store: T | null; isLoading: boolean; error: Error | null; } { const [store, setStore] = useState<T | null>(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState<Error | null>(null); const loadStore = useCallback(async () => { setIsLoading(true); setError(null); try { const loadedStore = await options.loader(); setStore(loadedStore); options.onLoad?.(loadedStore); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); options.onError?.(error); } finally { setIsLoading(false); } }, [options]); useEffect(() => { loadStore(); }, [loadStore]); return { store, isLoading, error }; }3.2 组件使用示例
import { useLazyStore