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

关于React组件重复渲染与无限渲染的两个技术疑问

关于React组件重复渲染与无限渲染的两个技术疑问

第一个问题:点击按钮为何只触发两次重渲染?

先看你提供的代码:

import React,{useState,useEffect} from 'react'
export function App(){
 const [a,setA]=useState(0)
 const handleClick = () => {
  setA(12)
 }
 console.log("rerendered")
 return <>
 <button onClick={handleClick}>Increment</button>
 {a}
 </>
}

咱们一步步拆解这个过程:

  • 组件首次挂载时,会执行一次完整渲染,此时console.log("rerendered")打印第一次,页面上a显示0。
  • 当你点击按钮时,触发handleClick回调调用setA(12),此时状态a从0更新为12,状态变化会触发组件重新渲染,这是第二次打印,页面上的a也同步更新为12。
  • 之后再点击按钮,你还是调用setA(12),但此时a的当前值已经是12了。React内部会对新旧状态做浅比较,发现两者完全一致,就会跳过这次无意义的重渲染,不会再执行组件函数,自然也就不会打印"rerendered"了。这是React内置的性能优化手段,避免不必要的渲染消耗。

第二个问题:直接在组件内调用setA为何会触发无限渲染?

再看这段代码:

import React,{useState,useEffect} from 'react'
export function App(){
 const [a,setA]=useState(0)
 setA(12)
 return <>
 {a}
 </>
}

这个情况和第一个问题的核心差异在于调用setState的时机:

  • 组件首次挂载时,执行函数体代码:先通过useState(0)初始化a为0,然后立刻调用setA(12)——这会触发组件重新渲染。
  • 第二次渲染时,组件函数再次执行:这里要注意,useState的初始值只在首次挂载时生效,第二次渲染时a的当前值其实是12,但你又在组件渲染的同步代码里调用了setA(12)。和事件回调里的setState不同,在**渲染阶段同步调用setState**时,React不会即时做浅比较优化——哪怕你设置的是和当前相同的值,也会标记组件需要重新渲染。于是就陷入了「渲染 -> 调用setA触发重渲染 -> 再次渲染 -> 再次调用setA」的无限循环。

简单总结:事件回调中的setState会先对比新旧状态,相同则跳过;但在组件渲染阶段同步执行的setState,哪怕值没变化,也会触发重渲染,最终导致无限循环。

备注:内容来源于stack exchange,提问作者user23957365

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 10:13:10