React组件函数在useEffect后重复执行及useLayoutEffect更新后useEffect仍执行的疑问
React组件渲染与生命周期钩子疑问
疑问点
- 组件函数中的代码为何会在useEffect执行后再次运行?
- 在useLayoutEffect中更新状态后,useEffect为何仍会执行?
示例代码
import { useEffect, useState, useLayoutEffect } from "react"; export default function App() { const [count, setCount] = useState(0); console.log("count in code: ", count); useEffect(() => { console.log("useEffect"); }, [count]); useLayoutEffect(() => { console.log("count in uselayout: ", count); setCount(1); }, [count]); return <button onClick={() => setCount(count + 1)}>{count}</button>; }
预期与实际日志
预期逻辑
首次渲染输出count in code: 0,接着执行useLayoutEffect和useEffect日志,随后useLayoutEffect的状态更新触发重渲染,再次输出count in code: 1、useLayoutEffect和useEffect日志。
实际输出
count in code: 0 count in uselayout: 0 useEffect (useLayoutEffect已更新状态,为何useEffect仍执行?不该被跳过吗?) count in code: 1 count in uselayout: 1 useEffect count in code: 1 (为何有这条额外日志?)
问题解答
1. 组件函数代码多次运行的原因
组件函数本身就是React的渲染入口,每次组件状态/ props变化时,React都会重新调用组件函数生成新的UI快照。你看到的额外count in code: 1,是开发环境下React严格模式(Strict Mode)的特性:严格模式会对组件函数、状态初始化、钩子回调进行重复调用,目的是检测潜在的副作用问题,生产环境不会出现该额外渲染。
2. useLayoutEffect更新状态后useEffect仍执行的原因
首次渲染的完整流程是:
- 调用组件函数,输出
count in code: 0 - 执行
useLayoutEffect(此时count为0),调用setCount(1)触发状态更新 - React立即同步触发重渲染,组件函数再次执行,输出
count in code:1,执行本次渲染的useLayoutEffect(count为1,不再触发状态更新) - 所有同步渲染完成后,React会执行之前已经调度好的首次渲染对应的useEffect(其依赖count=0已满足执行条件),之后再执行第二次渲染的useEffect(依赖count=1),因此会出现两次useEffect日志。
简单来说:首次渲染的useEffect已经进入调度队列,即使useLayoutEffect触发了重渲染,已经排队的useEffect仍会执行,不会被跳过。
关于额外的count in code:1日志
这是开发环境严格模式的重复渲染导致的。严格模式下,React会对每次有效渲染做一次额外的重复调用,因此第二次渲染(count=1)会被执行两次,产生两条count in code:1的日志,生产环境运行时该日志会消失。
内容的提问来源于stack exchange,提问作者user21357723
相关产品推荐
相关产品推荐

