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

React中通过API更新State遇警告:无法在状态转换中更新的解决方法

解决React "cannot update during an existing state transition" 警告

这个警告的核心原因很明确:你在render()方法里触发了状态更新。render()是React用来生成UI的纯渲染阶段,这个过程中绝对不能修改state——因为修改state会立刻触发新一轮的render,形成循环,同时违反了React的状态更新规则。

我们来拆解你的代码问题,然后一步步修正:

问题1:render里的定时器和状态更新逻辑

你在render()里放置了setTimeout,还在if(this.state.timePassed)判断里调用了get_BUS(内部包含setState)和setTimePassed,这直接导致渲染过程中触发状态更新,触发警告。

问题2:get_BUS里的setState写法错误

你原代码里的this.setState({ state: this.state[station].push(...) })有两个明显问题:

  • 错误地把更新的键写成了state,应该直接更新station1或station2
  • push是修改原数组的方法,React依赖状态的不可变性来检测变化,直接修改原数组不会触发组件重新渲染

问题3:废弃的生命周期方法

componentWillMount已经被React废弃,应该改用componentDidMount来做初始化数据请求和定时器设置。


正确的实现方式

我们把所有副作用(数据请求、定时器)移到合适的生命周期方法里,同时修正状态更新的写法:

export default class App extends React.Component {
  constructor() {
    super()
    this.state = {
      station1: [],
      station2: [],
    }
    // 保存定时器ID,方便组件卸载时清除
    this.refreshTimer = null;
  }

  // 修正get_BUS方法,使用不可变方式更新数组
  get_BUS = (code, station) => {
    fetch(`https://transportapi.com/v3/uk/bus/stop/${code}/live.json?app_id=6ab4b5a0&app_key=7693c12908e7d566351e3610b4acfa9f&group=route&nextbuses=yes`)
      .then((response) => response.json())
      .then((responseJson) => {
        // 整理新的公交数据
        const newBusData = [];
        for (const x in responseJson.departures) {
          const bus = responseJson.departures[x][0];
          newBusData.push(`${bus.line}: ${bus.aimed_departure_time}`);
        }
        // 使用函数式setState,确保基于最新状态更新
        this.setState(prevState => ({
          [station]: newBusData // 直接替换成新数组,如需追加可改为[...prevState[station], ...newBusData]
        }));
      })
      .catch((error) => {
        console.error(error);
      });
  }

  componentDidMount() {
    // 初始化加载数据
    this.get_BUS('01000053207', 'station1');
    this.get_BUS('01000053207', 'station2');
    
    // 设置定时刷新,每10秒更新一次
    this.refreshTimer = setInterval(() => {
      this.get_BUS('01000053207', 'station1');
      this.get_BUS('01000053207', 'station2');
    }, 10000);
  }

  componentWillUnmount() {
    // 组件卸载时清除定时器,防止内存泄漏
    if (this.refreshTimer) {
      clearInterval(this.refreshTimer);
    }
  }

  render() {
    // render只负责渲染UI,不做任何状态更新
    const { station1, station2 } = this.state;
    return (
      <div>
        <h2>Station 1</h2>
        <ul>
          {station1.map((bus, index) => (
            <li key={index}>{bus}</li>
          ))}
        </ul>
        <h2>Station 2</h2>
        <ul>
          {station2.map((bus, index) => (
            <li key={index}>{bus}</li>
          ))}
        </ul>
      </div>
    )
  }
}

关键改动说明

  1. 移除render里的副作用:把定时器和数据更新逻辑全部移到componentDidMount,这里是组件挂载完成后的安全阶段,可以放心执行副作用操作。
  2. 用setInterval代替setTimeout:如果需要每10秒重复刷新,setInterval比多次创建setTimeout更合适,记得在componentWillUnmount里清除定时器防止内存泄漏。
  3. 修正状态更新方式:使用函数式setState(prevState => ...)确保我们基于最新的状态进行更新,同时用不可变的方式生成新数组,保证React能检测到状态变化。
  4. 移除多余的timePassed状态:不需要这个状态来控制更新,直接用定时器触发刷新即可,简化逻辑。

这样修改后,你就不会再看到那个状态过渡期间更新的警告了,同时代码也更符合React的最佳实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:38:31