React中未设依赖的useEffect是否每次重渲染都执行?为何最后一次未触发ef1?
问题分析:为什么第三次重渲染未执行ef1?
你的代码核心是探究不同依赖项的useEffect执行机制,实际输出与预期的差异,根源在于React的异步状态更新、批量更新机制以及useEffect的执行规则,下面一步步拆解:
正确的执行流程(React 18)
1. 第一次渲染(初始渲染)
- 组件函数执行,输出
I'm in...,此时st1="",st2="" - 所有useEffect的setup函数依次执行(首次渲染时,无论依赖项如何都会执行):
- ef1(无依赖):输出
ef1 - ef2(空依赖数组):输出
ef2,调用setSt1("st1")→ 将更新加入队列 - ef3(依赖
st1):输出ef3,调用setSt2("st2")→ 将更新加入队列 - ef4(依赖
st1、st2):输出ef4
- ef1(无依赖):输出
- React合并队列中的
setSt1和setSt2更新,触发第二次渲染(批量更新优化,避免多次重渲染)
2. 第二次渲染
- 组件函数执行,输出
I'm in...,此时st1="st1",st2="st2" - 进入effect执行阶段:
- ef1(无依赖,每次渲染后必执行):输出
ef1 - ef2(空依赖数组,仅首次渲染执行):跳过
- ef3(依赖
st1:旧值""→ 新值"st1",依赖变化):输出ef3,调用setSt2("st2")→ 新值与当前st2("st2")完全相同,React不会触发重渲染 - ef4(依赖
st1、st2:st1变化):输出ef4
- ef1(无依赖,每次渲染后必执行):输出
此时不会出现第三次渲染,但你的实际输出有第三次I'm in...,说明你可能使用的是React 17或更早版本——这类版本中,effect内的setState不会被批量处理,且即使新值与旧值相同,也可能触发重渲染(开发模式下的调试行为)。
为什么第三次重渲染后没执行ef1?
如果确实出现了第三次渲染,那唯一的解释是:这次渲染是React开发模式下的严格模式重复渲染。
在React 18的严格模式中,开发环境下会对组件渲染进行一次"模拟卸载-重新挂载"的操作,以检测副作用问题。这次模拟的重新渲染:
- 会执行组件函数(输出
I'm in...) - 但会跳过effect的执行(因为是模拟操作,避免重复触发副作用)
这就是你看到第三次I'm in...后没有任何ef1输出的原因。
验证方法
你可以关闭严格模式(去掉index.js中的<StrictMode>标签),重新运行代码:
- 此时只会出现两次
I'm in... - 第二次渲染的effect阶段会正常执行ef1、ef3、ef4,不会有第三次渲染
内容的提问来源于stack exchange,提问作者Warren Hogan
相关产品推荐
相关产品推荐

