为何在组件主体中调用setState会引发无限渲染循环?
为什么在组件主体中设置相同状态值会触发无限渲染循环?
核心原因:渲染阶段调用setState的特殊行为
你之前的认知没错——React确实会通过Object.is比较新旧状态值,相同则不会触发重渲染,但这个逻辑的生效场景是在渲染完成后触发的状态更新(比如事件回调、useEffect中)。而如果是在**组件渲染过程中(组件主体代码执行阶段)**调用setState,规则完全不同:
渲染中调用setState会直接中断当前渲染,调度新渲染
当组件正在执行主体代码(比如你的示例里的setCount(1))时调用状态更新,React不会等到当前渲染完成再做值比较,而是会立即丢弃当前的渲染流程,直接调度一个新的渲染周期。无限循环的形成逻辑
在你的第一个示例中:- 第一次渲染时,执行
setCount(1),React中断当前渲染,启动新渲染 - 新渲染启动后,组件主体代码再次执行
setCount(1),再次中断当前渲染,调度下一次渲染 - 这个过程无限重复,因为每次渲染都没机会完成,也就不会触发React的“新旧值比较”逻辑来终止循环
- 第一次渲染时,执行
关于你第二个示例的现象解释
你观察到只打印Rendering...,没有Didmount和Unmount,原因是:
组件的挂载流程(useEffect的回调触发)只有在渲染完全完成后才会执行。而你的代码每次渲染都被setCount(1)中断,组件从未完成挂载,所以useEffect不会触发,卸载回调自然也不会执行。每次都是渲染到一半被打断重启,因此只会重复输出Rendering...。
正确的做法
永远不要在组件的渲染阶段(组件主体代码、useMemo/useCallback的依赖计算等同步执行的渲染逻辑中)直接调用状态更新方法。状态更新应该放到:
- 事件处理器(比如按钮点击回调)
useEffect钩子(针对副作用场景)- 其他异步回调(比如API请求完成后)
内容的提问来源于stack exchange,提问作者이주희
相关产品推荐
相关产品推荐

