避免布局抖动与视觉闪烁
识别 useEffect 导致明显闪烁的场景,并用 useLayoutEffect 修复
避免布局抖动与视觉闪烁 是 CoddyKit 上的免费 React Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 React Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 React Academy 课程共包含 4 节课。
什么是布局抖动
当 JavaScript 在循环中交替读取 DOM 属性和写入 DOM 时,就会发生布局抖动。每次写入后的读取都会强制浏览器同步重新计算布局,以返回准确值。这可能会把本应进行一次的布局计算变成几十次,严重损害性能。
React 批量更新的帮助
React 会将事件处理函数和副作用中的所有 setState 调用批量合并为一次重新渲染。这种自然的批处理可以避免单次渲染周期内导致布局抖动的读写读模式。在 React 18 中,批处理也扩展到了异步回调和承诺对象,从而减少并发状态更新造成的布局抖动。
useEffect 中出现闪烁的情况
当 useEffect 读取 DOM、更新状态并触发重新渲染时,浏览器会绘制两次:第一次使用初始状态,第二次使用修正后的状态,这就会产生闪烁。第一次绘制会短暂显示,然后被替换。对于调整高度、宽度或位置等布局属性的副作用,这种现象最为明显。
使用 DevTools 诊断闪烁
打开 Chrome DevTools,进入“渲染”标签页(通过“更多工具”下的三点菜单进入),然后启用“绘制闪烁”。发生重绘的区域会以绿色高亮显示。如果您看到某个组件在首次渲染时闪烁,然后立即重绘为不同的布局,就可以确认这是由 useEffect 驱动的状态更新造成的重复绘制。
将代码移至 useLayoutEffect 以修复闪烁
将 DOM 读取操作及其产生的状态更新从 useEffect 移至 useLayoutEffect。现在,相同的测量和状态更新会在绘制前同步完成,React 会在同一阶段重新渲染并提交更新,浏览器只会绘制最终的正确状态。DevTools 中的绿色闪烁也会消失。
单次绘制模式
避免闪烁的模式是:在 useLayoutEffect 中读取 DOM,使用测量结果调用 setState,React 同步重新渲染,提交修正后的 DOM,然后浏览器只使用最终结果绘制一次。这是设置工具提示位置、粘性页眉偏移量和动画的标准模式。
适合使用 useEffect 的场景
绝大多数副作用都应放在 useEffect 中:获取数据(加载时的闪烁是可以接受且符合预期的)、订阅事件或数据流、记录日志和分析、计时器,以及任何不会立即影响可见布局的副作用。在本可以使用 useEffect 的情况下过度使用 useLayoutEffect,是一种会损害性能的反模式。
适合使用 useLayoutEffect 的场景
请将 useLayoutEffect 保留给会反馈到视觉输出中的 DOM 测量操作,例如工具提示位置、基于元素尺寸的逻辑、滚动位置恢复,以及读取初始尺寸的动画设置。一个明确提示您应当切换的症状是:组件首次渲染时出现一帧可见的错误布局闪烁。
在代码中比较 useEffect 和 useLayoutEffect
这两个钩子具有完全相同的签名:useLayoutEffect(callback, deps) 与 useEffect(callback, deps)。唯一的区别在于回调运行的时机。您只需在代码中修改一个单词即可在两者之间切换。请先使用 useEffect,只有在确认出现闪烁后才改用 useLayoutEffect。
在同一组件中组合使用两者
在同一个组件中针对不同关注点使用这两个钩子是有效且常见的。例如,图表组件可以使用 useLayoutEffect 测量容器宽度并同步设置 SVG 的 viewBox,然后使用 useEffect 异步获取图表数据。每个钩子都负责处理对其而言时机重要的关注点。
测试重复绘制
除了使用 DevTools 的绘制闪烁功能外,您还可以在组件中添加控制台计数器来统计渲染次数。如果某个组件在首次挂载时记录了两次“render”——一次使用初始状态,一次使用修正后的测量结果——就说明出现了重复绘制的情况。将测量操作移至 useLayoutEffect 后,挂载完成后记录的渲染次数应减少为一次(不考虑严格模式下的重复执行)。
何时应优先使用 useLayoutEffect 而不是 useEffect
以下哪种情况是使用 useLayoutEffect 而不是 useEffect 的正确理由?
课程回顾:布局抖动与视觉闪烁
布局抖动源于交替读取和写入 DOM。React 的批处理机制可以阻止渲染过程中大多数此类问题。useEffect 测量 DOM 并更新状态时,会导致两次绘制,从而产生闪烁。请将 DOM 测量移至 useLayoutEffect 来修复闪烁。除此之外,默认使用 useEffect:获取数据、订阅、记录日志和计时器都应使用它。
常见问题解答
「避免布局抖动与视觉闪烁」课时是免费的吗?
是的 — 「避免布局抖动与视觉闪烁」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 React Academy 课程的其余内容,请升级到 CoddyKit PRO。 React Academy 课程共包含 4 节课。
「避免布局抖动与视觉闪烁」这节课中我会学到什么?
识别 useEffect 导致明显闪烁的场景,并用 useLayoutEffect 修复 你通过在浏览器中直接运行的动手代码来练习 React Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 React Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 React Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「避免布局抖动与视觉闪烁」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 React Academy 课中编写并运行代码吗?
能。每节 React Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。