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

如何避免React中useEffect因快速翻页导致的Axios重复请求?

解决React分页快速切换时的状态波动与重复请求问题

问题根源

  1. 竞态条件:快速切换页码时,多个API请求并行处理,旧请求可能晚于新请求返回,会覆盖最新的交易数据和页码状态,导致页面显示错乱。
  2. 无限循环触发:请求回调中更新paginationConfig时,使用了旧的状态对象展开,当返回的page与当前pageNo不一致时,会再次触发useEffect发起新请求,形成循环。

解决方案

1. 取消未完成请求

使用Axios的CancelToken,在页码变更或组件卸载时,取消上一次未完成的请求,避免旧请求干扰状态。

2. 优化状态更新逻辑

采用函数式状态更新获取最新状态,同时判断是否需要更新页码,避免不必要的useEffect触发。


修正后的完整代码

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

// 假设已定义的常量
const TRANSACTIONS_ENDPOINT = '/api/transactions';
const PAGE_STORAGE_KEY = 'currentPage';

function TransactionList() {
  const [transactions, setTransactions] = useState([]);
  const [paginationConfig, setPaginationConfig] = useState({
    pageNo: 1,
    totalPages: 0
  });
  const [searchConfig, setSearchConfig] = useState({
    search_by: '',
    search_value: ''
  });
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    // 创建新的取消令牌
    const cancelSource = axios.CancelToken.source();

    const fetchTransactions = async () => {
      setLoading(true);
      try {
        const response = await axios.get(TRANSACTIONS_ENDPOINT, {
          cancelToken: cancelSource.token,
          params: {
            page: paginationConfig.pageNo,
            search_by: searchConfig.search_by,
            search_value: searchConfig.search_value
          }
        });

        const { transactions, total_pages, page } = response.data;
        setTransactions(transactions);
        
        // 函数式更新,仅当返回页码与当前页码不同时才更新
        setPaginationConfig(prevState => {
          if (prevState.pageNo === page) return prevState;
          return {
            ...prevState,
            pageNo: page,
            totalPages: total_pages
          };
        });
        sessionStorage.setItem(PAGE_STORAGE_KEY, page.toString());
      } catch (err) {
        // 忽略主动取消的请求错误
        if (!axios.isCancel(err)) {
          console.error(err);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchTransactions();

    // 组件卸载或依赖变更时取消请求
    return () => {
      cancelSource.cancel('请求已取消');
    };
  }, [paginationConfig.pageNo, searchConfig.search_by, searchConfig.search_value]);

  // 分页切换处理函数示例
  const handlePageChange = (newPage) => {
    setPaginationConfig(prev => ({
      ...prev,
      pageNo: newPage
    }));
  };

  return (
    <div>
      {/* 交易表格渲染 */}
      {/* 分页导航组件 */}
    </div>
  );
}

export default TransactionList;

关键优化点

  • 请求取消机制:每次触发useEffect时生成新的取消令牌,同时在清理函数中取消当前请求,确保只有最新的请求能完成并更新状态。
  • 函数式状态更新:通过setPaginationConfig(prevState => ...)获取最新状态,避免闭包捕获旧值的问题,同时增加页码判断,防止无意义的状态更新触发useEffect循环。
  • 依赖数组细化:将searchConfig的属性拆分为单独依赖,避免因对象引用变化导致的不必要请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 13:35:08