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

React中使用useSWRInfinite(),如何避免时间戳触发重复请求?

解决useSWRInfinite因初始时间戳频繁变化导致重复请求的问题

问题根源

你当前代码中,timestamp在组件每次重渲染时都会重新生成(new Date().toISOString()会返回新的字符串),导致getKey返回的第一页请求Key不断变化。SWR会将不同的Key视为独立请求,因此频繁触发fetcher函数。

解决方案:固定初始时间戳

核心思路是让初始时间戳只在组件挂载时生成一次,避免随重渲染更新。下面提供两种可行实现:

方案一:使用useState初始化一次时间戳

利用useState的初始化函数特性,仅在组件首次挂载时生成初始时间戳:

const useQuestions = () => {
  const fetcher = async (url: string) => fetch(url).then((res) => res.json());

  // 仅在组件挂载时生成一次初始时间戳
  const [initialTimestamp] = useState(() => new Date().toISOString());

  const getKey = (pageIndex: number, previousPageData: any) => {
    if (previousPageData && !previousPageData.questions) return null;
    // 第一页使用固定的初始时间戳
    const cursorQuery = `?cursor=${pageIndex ? previousPageData?.from : initialTimestamp}`;
    if (pageIndex && !previousPageData?.cursor) return null;
    return `/api/questions${cursorQuery}`; // 修正原代码笔误:fromQuery → cursorQuery
  };

  const { data, size, setSize, error, isLoading, isValidating, mutate } = useSWRInfinite(getKey, fetcher, {
    initialSize: 1,
    revalidateAll: true,
    revalidateFirstPage: false,
    persistSize: true,
  });

  // 可选:手动刷新第一页的函数
  const refreshFirstPage = () => {
    const newTimestamp = new Date().toISOString();
    mutate(`/api/questions?cursor=${newTimestamp}`, undefined, { revalidate: true });
  };

  return { data, size, setSize, error, isLoading, isValidating, mutate, refreshFirstPage };
};

方案二:使用useMemo缓存时间戳

通过useMemo依赖空数组,确保时间戳仅计算一次:

const useQuestions = () => {
  const fetcher = async (url: string) => fetch(url).then((res) => res.json());

  // 缓存初始时间戳,仅在组件挂载时生成
  const initialTimestamp = useMemo(() => new Date().toISOString(), []);

  const getKey = (pageIndex: number, previousPageData: any) => {
    if (previousPageData && !previousPageData.questions) return null;
    const cursorQuery = `?cursor=${pageIndex ? previousPageData?.from : initialTimestamp}`;
    if (pageIndex && !previousPageData?.cursor) return null;
    return `/api/questions${cursorQuery}`;
  };

  const { data, size, setSize, error, isLoading, isValidating, mutate } = useSWRInfinite(getKey, fetcher, {
    initialSize: 1,
    revalidateAll: true,
    revalidateFirstPage: false,
    persistSize: true,
  });

  return { data, size, setSize, error, isLoading, isValidating, mutate };
};

额外说明

  • 原代码存在笔误:return /api/questions${fromQuery}应改为/api/questions${cursorQuery},否则请求URL会出错。
  • 如果需要主动刷新第一页数据,可以调用方案一中的refreshFirstPage函数,生成新的时间戳并触发SWR重验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:59:16