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

React如何忽略旧请求 仅处理最后一次API请求的返回数据

React Table 多筛选条件请求竞态问题解决方案

核心问题为异步请求竞态:短时间内发起的多个请求响应返回顺序和发起顺序不一致,导致旧请求的晚到响应覆盖最新数据,出现表格数据跳动。

方案1:使用AbortController取消过期请求(推荐)

原生浏览器API支持,直接取消未完成的过期请求,既避免旧响应处理,也减少无效的服务器资源占用和浏览器请求队列消耗。

import { useRef, useState, useEffect } from 'react';

function FilterTable() {
  const [tableData, setTableData] = useState([]);
  const [loading, setLoading] = useState(false);
  // 存储当前请求的取消控制器实例
  const abortCtrlRef = useRef(null);

  const fetchData = async (filters) => {
    // 发起新请求前先取消上一次未完成的请求
    if (abortCtrlRef.current) {
      abortCtrlRef.current.abort();
    }
    const currentAbortCtrl = new AbortController();
    abortCtrlRef.current = currentAbortCtrl;

    try {
      setLoading(true);
      const response = await fetch('/api/getTableData', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(filters),
        signal: currentAbortCtrl.signal
      });
      const result = await response.json();
      // 仅当前请求未被取消时才更新数据
      if (!currentAbortCtrl.signal.aborted) {
        setTableData(result);
      }
    } catch (error) {
      // 忽略主动取消请求产生的错误
      if (error.name !== 'AbortError') {
        console.error('数据请求失败:', error);
      }
    } finally {
      // 仅当前请求未被取消时才关闭加载状态
      if (!currentAbortCtrl.signal.aborted) {
        setLoading(false);
      }
    }
  };

  // 筛选条件变化时触发请求,filters为你的筛选、排序、搜索参数集合
  useEffect(() => {
    fetchData(filters);
    // 组件卸载时取消未完成的请求,避免内存泄漏
    return () => abortCtrlRef.current?.abort();
  }, [filters]);

  // 表格渲染逻辑...
}

方案2:请求ID标记法(兼容无取消能力的请求场景)

如果你的请求库不支持取消操作,可以通过标记请求ID的方式过滤旧请求的响应,仅处理最新发起的请求返回结果。

import { useRef, useState, useEffect } from 'react';

function FilterTable() {
  const [tableData, setTableData] = useState([]);
  const [loading, setLoading] = useState(false);
  // 存储最新一次请求的ID
  const latestReqIdRef = useRef(0);

  const fetchData = async (filters) => {
    const currentReqId = latestReqIdRef.current + 1;
    latestReqIdRef.current = currentReqId;

    try {
      setLoading(true);
      const response = await fetch('/api/getTableData', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(filters)
      });
      const result = await response.json();
      // 仅当前请求是最新发起的请求时才更新数据
      if (currentReqId === latestReqIdRef.current) {
        setTableData(result);
        setLoading(false);
      }
    } catch (error) {
      // 仅处理最新请求的报错
      if (currentReqId === latestReqIdRef.current) {
        console.error('数据请求失败:', error);
        setLoading(false);
      }
    }
  };

  useEffect(() => {
    fetchData(filters);
  }, [filters]);

  // 表格渲染逻辑...
}

额外优化建议

如果是搜索输入这类高频触发的操作,可以搭配防抖(debounce)逻辑,比如用户输入停止300ms后再发起请求,从源头减少不必要的并发请求,进一步提升体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 14:54:08