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

React类组件使用Axios请求OpenWeather API出现响应滞后数据跳变问题

问题根源

  • componentDidUpdate 未添加更新前置判断,组件任意更新都会触发接口请求,请求成功后调用 setState 会再次触发 componentDidUpdate,形成无限请求循环,多个异步请求返回顺序不可控,直接导致数据来回跳转
  • 存在接口请求竞态问题:多次触发请求时,后发起的请求可能比先发起的请求更早返回,旧请求的响应会覆盖新请求的正确数据
  • setState 中直接读取 this.state 计算派生状态,由于 setState 是异步批量更新的,可能读取到过期的状态值
  • 未处理组件卸载时的 pending 请求,若组件卸载后请求才返回,调用 setState 会抛出内存泄漏警告

修复方案

  1. 给 componentDidUpdate 添加触发请求的前置判断,仅当城市ID发生变更时才发起新请求,避免无限循环
  2. 抽离公共请求方法,复用逻辑的同时添加 axios 请求取消逻辑,每次发起新请求前取消前序未完成的请求,彻底解决竞态问题
  3. 改用函数式 setState 计算派生状态,保证读取到的是最新的状态值
  4. 组件卸载时主动取消未完成的请求,避免内存泄漏

修复后的完整代码示例:

class Weather extends Component {
  constructor(props) {
    super(props);
    this.state = {
      weatherData: undefined,
      weatherDescription: undefined,
      weatherTextDisplay: [],
      airConditionsText: [] // 注意你原有逻辑中用到的该状态需提前初始化
    };
    // 存储axios取消请求的方法
    this.cancelRequest = null;
  }

  // 抽离公共天气请求方法
  fetchWeatherData = () => {
    // 先取消之前未完成的请求,避免旧响应覆盖新数据
    if (this.cancelRequest) {
      this.cancelRequest("取消前序 pending 请求");
    }

    axios
      .get(
        `http://api.openweathermap.org/data/2.5/weather?id=${this.props.cityId}&units=metric&appid=myApiKey`,
        {
          // 配置取消令牌
          cancelToken: new axios.CancelToken(c => {
            this.cancelRequest = c;
          })
        }
      )
      .then((response) => {
        if (response.status === 200) {
          // 函数式setState,获取最新的状态值计算派生数据
          this.setState(prevState => ({
            weatherData: response.data.main.temp,
            weatherDescription: response.data.weather[0].description,
            weatherTextDisplay: prevState.airConditionsText.filter(item => item.id === response.data.weather[0].id)
          }));
        } else {
          throw new Error("请求异常");
        }
      })
      .catch((error) => {
        // 忽略主动取消的请求报错
        if (!axios.isCancel(error)) {
          console.error(error.message);
        }
      });
  };

  componentDidMount() {
    this.fetchWeatherData();
  }

  componentDidUpdate(prevProps) {
    // 仅当城市ID变更时才重新请求数据
    if (prevProps.cityId !== this.props.cityId) {
      this.fetchWeatherData();
    }
  }

  componentWillUnmount() {
    // 组件卸载时取消未完成的请求,避免内存泄漏
    if (this.cancelRequest) {
      this.cancelRequest("组件卸载,取消请求");
    }
  }

  // 原有渲染逻辑保持不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 15:24:04