Effect Hooks 的执行时机
如何判断 useEffect 的执行相对绘制有何保证?
- 一般情况: 非交互引起的 Effect 通常允许浏览器先绘制;由交互引起时 React 可能在绘制前运行 Effect,因此不能承诺它永远绘制后执行;
- 更新区别: 即使某次 Effect 在绘制前执行,内部状态更新也可能稍后处理;必须阻止错误布局被显示时评估 useLayoutEffect;
- 客户端限定: Effect 不在服务端渲染执行,不能用它生成服务端必须输出的内容;
- 同步生命周期: setup、cleanup、依赖与竞态的完整解释见 Effect 同步笔记,不在这里重复;
如何在浏览器显示前完成布局测量?
- Layout Effect: DOM 提交后、浏览器绘制前运行,适合测量尺寸后调整位置,避免用户看到第一次错误布局;
- 性能代价: 其代码和触发的同步更新会阻塞绘制,优先用普通 Effect,确实需要布局一致性时才使用;
- 服务端限制: 服务端没有可测量的布局,组件应设计合理初始内容或明确仅在客户端显示;
import { useLayoutEffect, useRef, useState } from "react";
function MeasuredBox() {
const ref = useRef(null);
const [height, setHeight] = useState(0);
useLayoutEffect(() => {
setHeight(ref.current.getBoundingClientRect().height);
}, []);
return <div ref={ref}>高度:{height}</div>;
}
CSS-in-JS 库何时使用 useInsertionEffect?
- 专门用途: 在其他布局 Effect 读取布局前插入样式,主要给 CSS-in-JS 库作者使用,不是应用代码的更快版 Effect;
- DOM 顺序: 可能在 DOM 更新前或后执行,不能依赖特定 DOM 更新时间;此时 ref 尚未关联,不能据此访问节点;
- 更新限制: 不在其内部更新 state;清理与建立按组件交错执行,不保证所有组件先清理再统一建立;