为何在React函数组件的函数体中设置状态会触发无限渲染?
React中设置相同状态时的渲染差异机制解析
通常当我们设置与当前值相同的状态时,React组件不会重新渲染,但这一规则在函数组件的函数体中直接调用状态更新函数时并不适用,以下是两种场景的对比:
场景1:事件回调中设置相同状态(无重新渲染)
function Test1() { const [name, setName] = useState("Shiva"); const onButtonClick = () => { console.log("Clicked"); setName("Shiva"); }; console.log("Rendering"); return ( <div> <span>My name is {name}</span> <button onClick={onButtonClick}>Click Me</button> </div> ); }
点击按钮时,虽然调用了setName并传入相同值,但组件不会重新渲染,控制台只会打印"Clicked",不会重复打印"Rendering"。
场景2:函数体中设置相同状态(无限循环)
function Test2() { const [name, setName] = useState("Shiva"); // ... some stuff setName("Shiva"); console.log("Rendering"); return ( <div> <span>My name is {name}</span> </div> ); }
组件会进入无限渲染循环,控制台会不断打印"Rendering"。
背后的内部机制
事件回调中的更新逻辑
React在处理事件回调(比如浏览器原生事件、合成事件)时,会进入批量更新模式。此时调用状态更新函数,React会先将更新任务加入队列,之后统一对新状态和当前状态做浅比较。如果发现值完全一致,就会跳过这次更新,不会触发组件重新渲染,这是React的性能优化手段。函数体中的更新逻辑
函数组件的函数体是每次渲染的执行入口,组件渲染时会同步执行函数体内的所有代码。当在函数体中直接调用状态更新函数时,React此时处于渲染执行阶段,不会先做状态对比,而是直接标记状态为待更新,并触发组件重新渲染。当组件重新渲染时,函数体再次执行,又会调用状态更新函数,如此往复就形成了无限循环。
简单总结:React在不同执行阶段对状态更新的处理逻辑不同——事件回调属于受控的批量更新,会拦截相同值的更新;而渲染过程中的同步更新则会直接触发渲染,不会提前拦截相同值的更新。
内容的提问来源于stack exchange,提问作者Shiva
相关产品推荐
相关产品推荐

