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

基于TanStack Query实现带延迟串行查询以规避Codeforces API限流

在TanStack Query中实现带延迟的串行API请求(适配Codeforces速率限制)

针对Codeforces API每2秒1次请求的限制,你可以通过以下几种便捷方式实现Q1、Q2、Q3的延迟串行执行,完全基于TanStack Query的原生能力:

方案一:利用enabled选项结合状态控制延迟

通过useQuery的enabled参数控制查询触发时机,配合定时器在指定延迟后开启后续请求:

import { useQuery, useState, useEffect } from '@tanstack/react-query';
// 假设这是你的API请求封装函数
const fetchUserData = (queryType) => {
  return fetch(`https://codeforces.com/api/${queryType}`).then(res => res.json());
};

function UserDataLoader() {
  // Q1:无延迟直接执行
  const { isSuccess: q1Success, isError: q1Error } = useQuery({
    queryKey: ['codeforces', 'q1'],
    queryFn: () => fetchUserData('user.info'),
  });

  // Q2:Q1成功后延迟2秒执行
  const [enableQ2, setEnableQ2] = useState(false);
  useEffect(() => {
    let timer;
    if (q1Success) {
      timer = setTimeout(() => setEnableQ2(true), 2000);
    } else if (q1Error) {
      setEnableQ2(false); // Q1失败则取消Q2
    }
    return () => clearTimeout(timer);
  }, [q1Success, q1Error]);

  const { isSuccess: q2Success } = useQuery({
    queryKey: ['codeforces', 'q2'],
    queryFn: () => fetchUserData('user.rating'),
    enabled: enableQ2,
  });

  // Q3:Q1成功后延迟4秒执行(或基于Q2成功延迟2秒,按需调整)
  const [enableQ3, setEnableQ3] = useState(false);
  useEffect(() => {
    let timer;
    if (q1Success) {
      timer = setTimeout(() => setEnableQ3(true), 4000);
    } else if (q1Error) {
      setEnableQ3(false);
    }
    return () => clearTimeout(timer);
  }, [q1Success, q1Error]);

  useQuery({
    queryKey: ['codeforces', 'q3'],
    queryFn: () => fetchUserData('user.status'),
    enabled: enableQ3,
  });

  return (
    <div>
      {q1Success && <p>Q1加载完成</p>}
      {q2Success && <p>Q2加载完成</p>}
    </div>
  );
}

优势:完全利用TanStack Query原生机制,每个查询独立维护缓存和状态,逻辑直观易调试。

方案二:使用prefetchQuery手动触发带延迟的查询

如果需要更主动的控制时机,可以用queryClient.prefetchQuery结合定时器,将数据预存入缓存,后续用useQuery读取:

import { useQuery, useQueryClient, useEffect } from '@tanstack/react-query';
import { fetchUserData } from './api';

function UserDataLoader() {
  const queryClient = useQueryClient();

  useEffect(() => {
    // 先执行Q1,完成后触发延迟的Q2和Q3
    const q1Promise = queryClient.prefetchQuery({
      queryKey: ['codeforces', 'q1'],
      queryFn: () => fetchUserData('user.info'),
    });

    q1Promise.then(() => {
      setTimeout(() => {
        queryClient.prefetchQuery({
          queryKey: ['codeforces', 'q2'],
          queryFn: () => fetchUserData('user.rating'),
        });
      }, 2000);

      setTimeout(() => {
        queryClient.prefetchQuery({
          queryKey: ['codeforces', 'q3'],
          queryFn: () => fetchUserData('user.status'),
        });
      }, 4000);
    }).catch(() => {
      // Q1失败时可取消后续请求
    });
  }, [queryClient]);

  // 从缓存中读取数据,自动处理加载/错误状态
  const q1Data = useQuery({ queryKey: ['codeforces', 'q1'], queryFn: () => fetchUserData('user.info') }).data;
  const q2Data = useQuery({ queryKey: ['codeforces', 'q2'], queryFn: () => fetchUserData('user.rating') }).data;
  const q3Data = useQuery({ queryKey: ['codeforces', 'q3'], queryFn: () => fetchUserData('user.status') }).data;

  return <div>{/* 渲染数据 */}</div>;
}

优势:适合需要手动触发查询的场景,预取数据不阻塞组件渲染。

方案三:封装自定义Hook实现复用逻辑

如果需要多次使用这种延迟串行查询,可以封装一个可复用的Hook:

import { useQuery, useState, useEffect } from '@tanstack/react-query';

function useDelayedQuery({ queryKey, queryFn, delay, trigger }) {
  const [enabled, setEnabled] = useState(false);

  useEffect(() => {
    let timer;
    if (trigger) {
      timer = setTimeout(() => setEnabled(true), delay);
    } else {
      setEnabled(false);
    }
    return () => clearTimeout(timer);
  }, [trigger, delay]);

  return useQuery({ queryKey, queryFn, enabled });
}

// 使用示例
function UserDataLoader() {
  const q1Query = useQuery({
    queryKey: ['codeforces', 'q1'],
    queryFn: () => fetchUserData('user.info'),
  });

  const q2Query = useDelayedQuery({
    queryKey: ['codeforces', 'q2'],
    queryFn: () => fetchUserData('user.rating'),
    delay: 2000,
    trigger: q1Query.isSuccess,
  });

  const q3Query = useDelayedQuery({
    queryKey: ['codeforces', 'q3'],
    queryFn: () => fetchUserData('user.status'),
    delay: 4000,
    trigger: q1Query.isSuccess,
  });

  return <div>{/* 渲染数据 */}</div>;
}

优势:代码更简洁,逻辑复用性强,减少重复代码。

注意事项

  1. 需处理请求失败的分支,比如Q1失败时是否取消后续请求,可结合isError状态调整触发逻辑。
  2. 确保延迟时间严格符合API限制,避免因网络延迟导致实际请求间隔不足2秒。
  3. TanStack Query的缓存机制会自动生效,重复渲染时不会重复触发请求,除非缓存过期或手动调用refetch。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 05:05:38