React函数组件调用setState为何触发两次重渲染?
问题复现代码
export const Component = () => { const [count, setCount] = useState<number>(0); const renderCount = useRef<number>(0); renderCount.current = renderCount.current + 1; return (<> <div>{`Rendered ${renderCount.current} times`}</div> <button type="button" onClick={() => setCount(count + 1)}>{`Clicked ${renderCount.current} times`}</button> </>); }
预期行为:点击按钮仅触发1次重渲染,count状态更新后完成UI重建即可
实际表现:每次点击按钮触发状态变更后,组件都会执行两次重渲染,渲染计数每次累加2
两次渲染的产生原因
这个是React 18+版本开发环境的正常设计,不是代码bug,核心触发原因是项目默认开启了严格模式(Strict Mode):
- 严格模式下React会在开发阶段主动重复执行组件渲染流程、重复走一遍挂载/卸载生命周期,目的是提前捕获代码里的不规范写法:比如渲染阶段产生的副作用污染、useEffect未编写清理逻辑等问题。这类重复渲染行为仅在开发环境存在,生产环境打包构建后不会触发。
- 你把
renderCount.current自增的逻辑直接写在了组件函数体的渲染执行阶段,没有做任何隔离,严格模式下每次状态更新触发的渲染流程都会被React执行2次,所以计数每次会累加2,看起来就像是触发了两次重渲染。 - 如果要验证逻辑,可以临时移除项目入口文件里根组件外层的
<StrictMode>包裹,此时点击按钮就只会触发1次渲染,但不推荐日常开发中关闭严格模式,它能帮你提前规避很多隐蔽的代码问题。 - 额外提一句示例代码本身的逻辑问题:按钮上的点击次数展示写法是错误的,点击次数应该绑定
count这个状态值,而不是记录渲染次数的ref。ref值变化本身不会触发视图更新,这里只是刚好ref值和渲染流程同步才显示出数字,业务逻辑上不应该这么写。
内容的提问来源于stack exchange,提问作者user6118986
相关产品推荐
相关产品推荐

