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

使用Apollo时多Lazy Query轮询仅生效最后一个的解决方法

解决Apollo多个带轮询的查询同时运行的问题

问题原因

你使用的useLazyQuery返回的loadData函数绑定到同一个钩子实例,每次调用loadData都会覆盖当前钩子的查询配置(包括pollInterval),同时终止之前的轮询任务。循环结束后,只有最后一次调用的查询会持续轮询,之前的查询全部被终止,这就是你只看到最后一个条目重复输出的原因。

解决方案

方案1:将每个查询封装为独立组件

把单个条目的查询逻辑拆成独立组件,每个组件内部使用专属的useLazyQuery,让每个查询拥有独立的轮询上下文,避免互相干扰。

示例代码:

// 单个数据查询组件
const DataPollingItem = ({ dataId, idx }: { dataId: string; idx: string }) => {
  const [loadData] = useLazyQuery(getData, {
    pollInterval: 3000,
    notifyOnNetworkStatusChange: true,
    onCompleted: () => {
      console.log('loaded', idx);
      void onboardData(idx, dataId);
    },
    onError: (e) => {
      console.log('error', idx);
    },
  });

  // 组件挂载时触发初始查询
  useEffect(() => {
    void loadData({ variables: { id: dataId } });
  }, [dataId, loadData]);

  return null; // 无需渲染UI内容
};

// 父组件中调用
const ParentComponent = () => {
  // 假设yourData是你的目标数据集合
  const yourData = {/* 你的数据内容 */};

  return (
    <>
      {Object.entries(yourData).map(([idx, item]) => (
        <DataPollingItem key={idx} dataId={item.id} idx={idx} />
      ))}
    </>
  );
};

方案2:手动管理轮询(不依赖useLazyQuery的pollInterval)

直接使用Apollo Client的client.query方法,为每个条目单独设置定时器实现轮询,完全掌控每个查询的生命周期。

示例代码:

import { useApolloClient } from '@apollo/client';

const YourComponent = () => {
  const client = useApolloClient();
  // 用ref存储每个条目的定时器,方便后续清除
  const timersRef = useRef<Record<string, NodeJS.Timeout>>({});

  const startPolling = async (dataEntries: [string, any][]) => {
    // 先清除之前的定时器,避免重复轮询
    Object.values(timersRef.current).forEach(timer => clearInterval(timer));
    timersRef.current = {};

    for (const [idx, item] of dataEntries) {
      const dataId = item.id;
      // 定义单次查询逻辑
      const runQuery = async () => {
        try {
          await client.query({
            query: getData,
            variables: { id: dataId },
          });
          console.log('loaded', idx);
          void onboardData(idx, dataId);
          // 如果查询成功,可选择停止该条目的轮询
          // clearInterval(timersRef.current[idx]);
        } catch (e) {
          console.log('error', idx);
        }
      };

      // 立即执行一次查询,再启动轮询
      await runQuery();
      timersRef.current[idx] = setInterval(runQuery, 3000);
    }
  };

  // 组件卸载时清除所有定时器
  useEffect(() => {
    return () => {
      Object.values(timersRef.current).forEach(timer => clearInterval(timer));
    };
  }, []);

  return (
    <button onClick={() => startPolling(Object.entries(yourData))}>
      启动轮询
    </button>
  );
};

关键说明

  • 方案1遵循React钩子规则,实现简单,适合逻辑不复杂的场景。
  • 方案2灵活性更高,支持自定义轮询启停逻辑(比如查询成功后停止该条目轮询),适合复杂业务需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:18:18