为何这段React代码最后一次渲染时未执行useEffect Hooks?
React组件重新渲染但不执行useEffect的原因分析
问题代码
import React, { useState, useEffect, useRef } from "react"; import ReactDOM from "react-dom"; function Example() { const [test, setTest] = useState("init"); const renderNum = useRef(0); console.log("renderNum: ", renderNum.current); renderNum.current++; useEffect(() => { console.log("first useEffect value: ", test); setTest("newval"); }); useEffect(() => { console.log("useEffect value: ", test); }); return <div>{test + renderNum.current}</div>; } const rootElement = document.getElementById("root"); ReactDOM.render(<Example />, rootElement);
实际输出
renderNum: 0 first useEffect value: init useEffect value: init renderNum: 1 first useEffect value: newval useEffect value: newval renderNum: 2
原因解析
状态更新的bailout机制:
当第二次渲染的useEffect中调用setTest("newval")时,test的当前值已经是"newval"——新值与当前状态完全相同。此时React会触发一次bailout渲染:- 组件函数会被执行(所以
renderNum继续递增,输出renderNum: 2),这是因为React需要执行组件逻辑,对比虚拟DOM是否发生变化。 - 但React会跳过
useEffect这类副作用的执行,因为状态没有实际变更,副作用依赖的核心变量未发生变化,执行副作用属于不必要的性能消耗。
- 组件函数会被执行(所以
为什么不直接跳过这次渲染?
React的设计逻辑是:即使setState传入相同值,也不会直接跳过组件渲染——因为组件输出可能依赖state之外的变量(比如例子中的renderRef),必须执行组件函数后对比虚拟DOM,才能决定是否更新真实DOM。但由于状态本身无变更,React会跳过副作用执行流程。关于useEffect的执行条件:
你的两个useEffect都未设置依赖数组,默认会在每次常规渲染完成后执行,但bailout渲染属于特殊场景——React判定状态无变更,因此跳过了副作用的执行。
内容的提问来源于stack exchange,提问作者Elliot Lynde
相关产品推荐
相关产品推荐

