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

React多async/await调用报RangeError: Maximum call stack size exceeded

RangeError: Maximum call stack size exceeded 问题修复

报错根因

这个调用栈溢出和异步函数调用数量无关,核心是函数名遮蔽触发无限递归,同时代码存在React状态时序错误、直接修改状态的逻辑问题:

  • 自定义请求入口函数命名为fetch,和浏览器全局fetch API重名,产生作用域遮蔽:fetchRides、fetchUser内部调用fetch发请求时,实际拿到的是当前作用域下自定义的fetch函数,导致执行流无限递归调用自身,最终撑爆调用栈。
  • React的setState是异步批处理逻辑,接口请求完成后立即读取updatedRides、user状态,拿到的是渲染闭包里的初始旧值,距离计算逻辑拿不到正确的接口返回数据。
  • 直接给状态里的ride对象挂载distance属性,违反React状态不可变原则,会引发渲染不更新、状态不一致问题。

修复后完整代码

import { useState, useEffect } from "react";
import Navbar from "./Navbar";

const Rides = () => {
  const [rides, setRides] = useState([]);
  const [user, setUser] = useState({});
  const [updatedRides, setUpdatedRides] = useState([]);

  useEffect(() => {
    const fetchRides = async () => {
      const data = await fetch('https://assessment.api.vweb.app/rides');
      return await data.json();
    }

    const fetchUser = async () => {
      const data = await fetch('https://assessment.api.vweb.app/user');
      return await data.json();
    }

    const calculateDistance = (path, user_station) => {
      let min = Math.abs(user_station - path[0]);
      for(let i = 0; i<path.length; i++){
        if(path[i] === user_station){
          return 0;
        }
        if(Math.abs(path[i] - user_station) < min){
          min = Math.abs(path[i] - user_station);
        }
      }
      return min;
    }
    
    // 重命名入口函数,避免和全局fetch重名导致作用域遮蔽
    const loadInitialData = async() => {
      // 无依赖的接口用Promise.all并行拉取,缩短加载时间
      const [ridesData, userData] = await Promise.all([
        fetchRides(),
        fetchUser()
      ]);
      
      // 直接基于接口返回值计算距离,不依赖中间状态更新,规避闭包旧值问题
      const ridesWithDistance = ridesData.map((ride) => ({
        ...ride,
        distance: calculateDistance(ride.station_path, userData.station_code)
      }));

      // 批量更新状态
      setRides(ridesData);
      setUser(userData);
      setUpdatedRides(ridesWithDistance);
    }

    loadInitialData().catch((e) => {
      console.log(e);
    })

  }, [])

  return(
    <div>
      <Navbar user={user}/>
      <div className="rides">
        {updatedRides.map((ride) => (
          <div className="rideDetail" key={ride.id}>
            <img src={ride.map_url} alt="Ride_map" />
            <div>
              <p>Ride Id : {ride.id}</p>
              <p>Origin Station : {ride.origin_station_code}</p>
              <p>Station Path : {ride.station_path.join(', ')}</p>
              <p>Date : {ride.date}</p>
              <p>Distance : {ride.distance}</p>
            </div>
          </div>
        ))}
      </div>
    </div>
  )
}

export default Rides;

修复说明

  • 把原自定义的fetch入口函数重命名为loadInitialData,彻底解决函数名遮蔽导致的无限递归问题,从根源消除调用栈溢出报错。
  • 调整数据流转逻辑:接口返回数据后直接计算距离,不依赖React状态更新后的取值,避免拿到旧闭包值导致计算错误。
  • 距离计算时通过展开运算符生成新的ride对象,不直接修改原始响应数据,符合React不可变数据要求。
  • 补充React hooks的导入,给列表项添加唯一key属性,对无依赖的接口请求改为并行拉取,优化加载性能。

内容的提问来源于stack exchange,提问作者Anuj kumar Jaimini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 15:03:23