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

为何React在该示例中触发3次渲染而非2次?

为什么React会触发第三次渲染?

以下是示例代码:

const {useEffect, useState} = React;

const App = () => {

  const [timer, setTimer] = useState(0);

  const addTimer = () => {
    console.log('timer', timer);
    setTimer(timer + 1);
  }

  useEffect(() => {
    console.log('Use effect');
  
    setInterval(addTimer, 8000);
  }, [])


  return <h5>Time: {console.log('Render') || timer}</h5>;
};

ReactDOM.createRoot(document.querySelector('#root')).render(<App />);

对应的HTML:

<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

控制台输出:

Render
Use effect
timer 0
Render
timer 0
Render
timer 0 (infinity)

已知前提:

  • 首次Render是组件初始渲染,useEffect执行后启动定时器
  • addTimer因闭包问题始终读取初始的timer=0,此部分无需解释
  • 第一次定时器触发时,调用setTimer(0+1)将状态从0更新为1,触发第二次Render
  • 第二次定时器触发时,调用setTimer(0+1)尝试将状态从1更新为1(值未变化),但仍触发了第三次Render,之后每次定时器触发仅输出timer 0不再触发渲染

核心原因解释

React的状态更新机制中,即使新状态和当前状态值相同,首次遇到该情况时仍会触发一次组件渲染函数执行——这是因为React默认不会对状态值做前置的「浅比较」来跳过渲染流程,只有在确认新旧状态完全一致后,后续的重复更新才会被优化跳过。

具体到这个场景:

  1. 第二次定时器触发时,调用setTimer(1)(闭包中timer始终为0),此时组件当前状态已经是1,表面看值未变化
  2. React会先将这次更新加入队列,触发完整的渲染流程,因此组件渲染函数执行,输出第三次Render
  3. 在渲染的后期阶段,React对比新旧状态发现值完全一致,最终不会更新DOM
  4. 后续定时器再次触发时,同样调用setTimer(1),React会识别到这是重复的无意义更新,直接跳过渲染流程,因此不再输出Render

这种行为是React的设计逻辑:优先保证状态更新流程的完整性,仅在重复遇到相同值的状态更新时,才会启动优化跳过渲染。

注:该现象在React 16.8.0、17.0.0、18.1.0版本中均存在,与版本无关。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 04:54:12