You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在闭包中调用Zustand create时状态更新不生效的问题

问题原因与修复方案

核心原因

  1. 重复创建Store实例:每次组件渲染时,usePaginationData(mockPageDataRequest)()都会重新执行create方法,生成全新的Zustand Store实例。组件每次拿到的都是新Store的初始状态,自然看不到之前Store中isLoading的变化。
  2. 状态监听方式错误:直接在组件渲染阶段打印isLoading,这里打印的是当前渲染周期的状态快照,不会自动追踪后续状态更新。

修复代码

第一步:改造自定义Store Hook,实现单例缓存

// 用WeakMap缓存不同requestMethod对应的Store实例,避免重复创建
const storeCache = new WeakMap();

export const usePaginationData = (requestMethod) => {
  // 不存在对应Store时才创建
  if (!storeCache.has(requestMethod)) {
    const store = create((set, get) => ({
      data: [],
      page: 1,
      isLoading: false,
      fetchMore: async () => {
        set({ isLoading: true });
        try {
          const newData = await requestMethod(get().page, 10);
          set((state) => ({
            data: [...state.data, ...newData.data],
            page: state.page + 1 // 必须更新页码,否则每次请求同一页数据
          }));
        } finally {
          set({ isLoading: false }); // 请求完成(成功/失败)都重置加载状态
        }
      },
    }));
    storeCache.set(requestMethod, store);
  }
  
  // 返回缓存后的Store的useStore钩子
  return storeCache.get(requestMethod);
};

第二步:组件中正确调用并监听状态

import { useEffect } from 'react';

// 直接调用返回的useStore钩子,符合React Hook规则
const { data, isLoading, fetchMore } = usePaginationData(mockPageDataRequest)();

// 用useEffect监听isLoading的变化,才能打印实时状态
useEffect(() => {
  console.log('isLoading', isLoading);
}, [isLoading]);

return (
  <button onClick={fetchMore} disabled={isLoading}>
    {isLoading ? '加载中...' : '加载更多'}
  </button>
);

关键说明

  • WeakMap缓存:利用WeakMap的特性,当requestMethod函数被垃圾回收时,对应的Store也会自动清理,不会造成内存泄漏。
  • 单例Store:同一requestMethod只会创建一次Store,组件每次拿到的都是同一个Store的状态,状态更新会触发组件重新渲染。
  • 状态监听:组件渲染阶段的console.log只能打印当前渲染的状态值,要追踪状态变化必须用useEffect监听依赖项。
  • 完善逻辑:补充了页码更新和finally块重置isLoading,避免请求失败时一直显示加载状态,同时防止重复请求同一页数据。

内容的提问来源于stack exchange,提问作者Kent Wood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 10:33:11