为何useLayoutEffect可避免页面闪烁?结合渲染时机的困惑
为什么useLayoutEffect能避免页面闪烁?
先明确React更新流程的核心逻辑,这是解开疑惑的关键:
- 当状态变化触发渲染时,React会先完成组件的渲染计算(执行组件函数生成新JSX),进入DOM更新环节
- 在浏览器屏幕重绘之前,React会同步执行所有
useLayoutEffect钩子 - 如果
useLayoutEffect里更新了状态,React会同步触发新一轮的渲染计算+DOM更新,整个过程完全在重绘前完成 - 所有
useLayoutEffect执行完毕、所有同步渲染完成后,浏览器才会进行屏幕重绘 - 最后,浏览器空闲时才会异步执行
useEffect钩子
结合你的代码示例拆解
初始渲染的完整流程:
- 组件第一次执行,
count为0,打印count in code: 0 - React执行
useLayoutEffect,此时count是0,调用setCount(1) - 这个状态更新会同步触发第二次渲染:组件再次执行,
count为1,打印count in code: 1 - 第二次渲染后,
useLayoutEffect的依赖是count=1,不会再触发状态更新 - 到这里所有重绘前的流程全部完成,浏览器直接重绘显示
count=1的按钮,你不会看到短暂的0状态,自然没有闪烁 - 最后浏览器空闲时,执行两次
useEffect:第一次对应count=0的渲染,第二次对应count=1的渲染,所以会打印两次count in useeffect
对比useEffect的差异
如果把setCount(1)放到useEffect里:
- 组件第一次执行,
count=0,浏览器直接重绘显示0 - 之后
useEffect执行,调用setCount(1)触发渲染,屏幕才更新为1 - 这个过程中你会看到按钮从
0闪到1,这就是useLayoutEffect要解决的问题
你的误解在于:以为useLayoutEffect执行后浏览器就直接重绘,但实际上useLayoutEffect里的状态更新会触发同步渲染,所有这些步骤都在重绘前完成,屏幕最终只显示最后一次渲染的结果,不会暴露中间的旧状态。
内容的提问来源于stack exchange,提问作者user21357723
相关产品推荐
相关产品推荐

