useLayoutEffect和useEffect区别详解
useLayoutEffect 和 useEffect 是 React 中用于处理副作用的两个钩子,它们的核心区别在于 执行时机 和 对渲染流程的影响。以下是详细对比:
1. 执行时机对比
useLayoutEffect | useEffect | |
|---|---|---|
| 触发时机 | 在 DOM 更新后、浏览器绘制前 同步执行 | 在 DOM 更新后、浏览器绘制后 异步执行 |
| 执行顺序 | 先执行 | 后执行 |
| 代码示例 | useLayoutEffect(() => {// 同步立即执行}) | useEffect(() => {// 异步延迟执行}) |
2. 对渲染的影响
useLayoutEffect | useEffect | |
|---|---|---|
| 是否阻塞渲染 | ✅ 会阻塞浏览器绘制 | ❌ 不阻塞渲染 |
| 适用场景 | 需要同步读取/修改 DOM 布局的场景 | 数据获取、事件监听等非紧急操作 |
| 风险提示 | 过度使用会导致页面卡顿 | 无显著性能风险 |
3. 典型使用场景
适合用 useLayoutEffect 的情况:
-
读取或修改 DOM 尺寸/布局
useLayoutEffect(() => { const width = divRef.current.offsetWidth; setWidth(width); // 同步更新避免闪烁 }, []); -
同步状态到 DOM
useLayoutEffect(() => { inputRef.current.value = state; // 立即更新输入框值 }, [state]); -
动画起始状态设置
useLayoutEffect(() => { element.style.transform = 'scale(1)'; // 避免初始闪烁 }, []);
适合用 useEffect 的情况:
-
数据获取
useEffect(() => { fetchData().then(setData); }, []); -
事件监听
useEffect(() => { window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); -
非紧急副作用
useEffect(() => { analytics.log('Component mounted'); }, []);
4. 执行流程问题图解

sequenceDiagram
React->>DOM: 更新虚拟DOM
React->>DOM: 应用变更到真实DOM
rect rgb(200, 150, 255)
Note right of React: useLayoutEffect
React->>useLayoutEffect: 同步执行
end
Browser->>Paint: 浏览器绘制页面
rect rgb(150, 255, 150)
Note right of Browser: useEffect
Browser->>useEffect: 异步执行
end
5. 性能注意事项
useLayoutEffect的风险- 长时间运行的逻辑会阻塞页面渲染
- 在服务端渲染 (SSR) 中会导致警告(需替换为
useEffect)
- 黄金法则
- 默认先用
useEffect - 只有遇到视觉闪烁/布局问题时才用
useLayoutEffect
- 默认先用
6. 代码示例:避免闪烁
function Tooltip() {
const [position, setPosition] = useState({ top: 0, left: 0 });
const ref = useRef();
// 用 useLayoutEffect 避免位置闪烁
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
setPosition({ top: height + 10, left: 0 });
}, []);
return (
<div ref={ref} style={{ position: 'absolute', ...position }}>
Tooltip
</div>
);
}
7. 总结选择标准
| 问题类型 | 应选钩子 |
|---|---|
| “我需要读取/修改 DOM 布局” | useLayoutEffect |
| “我要获取数据或添加事件” | useEffect |
| “用户会看到中间状态闪烁” | useLayoutEffect |
| “副作用不紧急” | useEffect |
595

被折叠的 条评论
为什么被折叠?



