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

React+TS中用useQuery实现指标数据增量更新的方法

实现增量更新指标数据的方案

要实现首次加载10分钟数据、后续每30秒增量拉取并维护内存数据的需求,可以通过TanStack React Query的缓存读取与数据合并逻辑来完成,具体实现如下:

核心思路

  1. 首次请求:拉取最近10分钟的全量数据。
  2. 后续增量请求:每次仅拉取最近30秒的新数据。
  3. 数据合并与清理:将新数据追加到现有缓存中,同时过滤掉超过10分钟的旧数据,保证内存中始终保留最新10分钟的指标。

完整代码实现

import { useQuery, useQueryClient } from '@tanstack/react-query';
import { subMinutes, subSeconds, isAfter, parseISO } from 'date-fns';

// 定义指标数据类型(根据实际API返回结构调整)
interface MetricData {
  timestamp: string; // ISO格式时间字符串
  value: number;
  // 其他字段...
}

// 假设的API请求函数(替换为实际接口调用)
const getMetrics = async (
  metricId: string,
  params: { startAt: string; endAt: string }
): Promise<MetricData[]> => {
  const response = await fetch(
    `/api/metrics/${metricId}?startAt=${params.startAt}&endAt=${params.endAt}`
  );
  if (!response.ok) throw new Error('Failed to fetch metrics');
  return response.json();
};

// 组件内使用
const MetricComponent = ({ metricId }: { metricId: string }) => {
  const queryClient = useQueryClient();

  const { data: metricData, isLoading, isFetching } = useQuery({
    queryKey: ['fetch-metric', metricId],
    queryFn: async () => {
      const now = new Date();
      // 读取当前缓存中的已有数据
      const existingData = queryClient.getQueryData<MetricData[]>(['fetch-metric', metricId]);

      let newData: MetricData[];
      if (!existingData) {
        // 首次请求:拉取最近10分钟数据
        const startAt = subMinutes(now, 10);
        newData = await getMetrics(metricId, {
          startAt: startAt.toISOString(),
          endAt: now.toISOString(),
        });
      } else {
        // 后续增量请求:拉取最近30秒数据
        const startAt = subSeconds(now, 30);
        newData = await getMetrics(metricId, {
          startAt: startAt.toISOString(),
          endAt: now.toISOString(),
        });
      }

      // 合并新旧数据,过滤掉超过10分钟的旧数据
      const tenMinutesAgo = subMinutes(now, 10);
      const combinedData = [...(existingData || []), ...newData].filter(item => {
        const itemTimestamp = parseISO(item.timestamp);
        return isAfter(itemTimestamp, tenMinutesAgo);
      });

      // 去重(避免API返回重复的时间点数据)
      const uniqueData = Array.from(
        new Map(combinedData.map(item => [item.timestamp, item])).values()
      );

      // 按时间戳升序排序,保证数据顺序正确
      uniqueData.sort((a, b) => parseISO(a.timestamp).getTime() - parseISO(b.timestamp).getTime());

      return uniqueData;
    },
    refetchOnWindowFocus: true,
    refetchInterval: 30000, // 每30秒自动刷新
  });

  return (
    <div>
      {isLoading ? (
        <p>加载中...</p>
      ) : (
        <div>
          {isFetching && <p>更新数据中...</p>}
          {/* 渲染指标数据 */}
          {metricData?.map(metric => (
            <div key={metric.timestamp}>
              <span>{metric.timestamp}</span>
              <span>{metric.value}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

export default MetricComponent;

关键细节说明

  • 缓存读取:通过queryClient.getQueryData获取当前缓存的指标数据,判断是否为首次请求。
  • 增量请求:后续请求仅拉取最近30秒的数据,减少API传输量。
  • 数据清理:使用date-fns的isAfter过滤掉超过10分钟的旧数据,自动维持10分钟的时间窗口。
  • 去重与排序:通过Map基于时间戳去重,避免重复数据;排序保证数据按时间顺序展示。
  • 状态区分:用isLoading标识首次加载状态,isFetching标识后续增量更新状态,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 06:45:00