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

React函数组件Axios重复调用致浏览器崩溃问题求助

解决React组件重复调用API导致崩溃的问题 + 进度条实现

核心问题分析

你的问题根源在于API调用逻辑没有被正确限制执行时机:函数组件每次重渲染都会从头执行代码,如果API调用直接写在组件顶层,每次状态更新(比如更新progress)都会触发重渲染,进而再次调用API,形成无限循环,最终导致浏览器崩溃。全局变量started无法被React追踪,反而会破坏组件状态的一致性,导致渲染异常。

解决方案步骤

1. 用useEffect控制API调用时机

将所有API调用逻辑放到useEffect钩子中,并设置空依赖数组[],确保只在组件首次挂载时执行一次。同时用isLoading状态标记加载状态,防止重复触发调用。

2. 安全更新进度状态

更新进度时使用函数式更新(setProgress(prev => prev + step)),避免依赖外部变量导致的状态不同步;或者用useRef跟踪当前完成的请求数,减少不必要的重渲染。

3. 批量处理详情API调用

用Promise.all或Promise.allSettled批量请求详情数据,同时逐个更新进度。注意用Axios的取消令牌(CancelToken)在组件卸载时取消未完成的请求,防止内存泄漏。

4. 实现简易进度条

通过状态控制进度条的宽度,结合加载状态展示UI,让用户清晰看到加载进度。

完整代码示例

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

function App() {
  const [pokemonList, setPokemonList] = useState([]);
  const [progress, setProgress] = useState(0);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState('');
  const cancelTokenRef = useRef(null); // 用于取消Axios请求

  useEffect(() => {
    // 创建取消令牌
    cancelTokenRef.current = axios.CancelToken.source();

    const fetchPokemonData = async () => {
      try {
        // 1. 获取汇总数据
        const summaryRes = await axios.get('https://pokeapi.co/api/v2/pokemon?limit=20', {
          cancelToken: cancelTokenRef.current.token
        });
        const pokemonUrls = summaryRes.data.results.map(item => item.url);
        const total = pokemonUrls.length;
        let completed = 0;

        // 2. 批量请求详情数据,逐个更新进度
        const pokemonPromises = pokemonUrls.map(async (url) => {
          const detailRes = await axios.get(url, {
            cancelToken: cancelTokenRef.current.token
          });
          // 每完成一个请求就更新进度
          completed++;
          setProgress(Math.round((completed / total) * 100));
          return detailRes.data;
        });

        // 等待所有请求完成
        const detailedPokemon = await Promise.all(pokemonPromises);
        setPokemonList(detailedPokemon);
      } catch (err) {
        if (!axios.isCancel(err)) {
          setError('加载数据失败,请稍后重试');
        }
      } finally {
        setIsLoading(false);
        setProgress(100); // 加载完成后进度设为100%
      }
    };

    // 只有在未加载时才执行
    if (isLoading) {
      fetchPokemonData();
    }

    // 组件卸载时取消请求
    return () => {
      if (cancelTokenRef.current) {
        cancelTokenRef.current.cancel('组件已卸载,取消请求');
      }
    };
  }, [isLoading]); // 依赖isLoading,确保状态变化时能正确控制

  // 渲染UI
  return (
    <div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
      <h1>Pokemon列表</h1>
      
      {/* 进度条 */}
      {isLoading && (
        <div style={{ height: '8px', backgroundColor: '#eee', borderRadius: '4px', marginBottom: '20px' }}>
          <div 
            style={{ 
              height: '100%', 
              width: `${progress}%`, 
              backgroundColor: '#4CAF50', 
              borderRadius: '4px',
              transition: 'width 0.3s ease'
            }} 
          />
        </div>
      )}
      
      {/* 错误提示 */}
      {error && <p style={{ color: 'red' }}>{error}</p>}
      
      {/* 加载完成后展示列表 */}
      {!isLoading && !error && (
        <ul style={{ listStyle: 'none', padding: 0 }}>
          {pokemonList.map(pokemon => (
            <li key={pokemon.id} style={{ padding: '10px', borderBottom: '1px solid #eee' }}>
              <img 
                src={pokemon.sprites.front_default} 
                alt={pokemon.name} 
                style={{ width: '50px', height: '50px', marginRight: '10px' }}
              />
              <span style={{ textTransform: 'capitalize' }}>{pokemon.name}</span>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

export default App;

关键细节说明

  • useEffect依赖项:这里依赖isLoading,确保只有在加载状态为true时才执行请求,避免重复触发。
  • 进度更新优化:用completed变量跟踪完成数,每次完成请求后更新进度,函数式更新也可以写成setProgress(prev => Math.round(((prev / 100) * total + 1) / total * 100)),效果一致。
  • 请求取消:通过CancelToken在组件卸载时取消未完成的请求,防止内存泄漏和控制台报错。
  • 进度条动画:给进度条添加transition属性,让进度变化更平滑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 03:17:16