React中useEffect和useLayoutEffect的区别

在最近一次面试中被问到,我印象中好像从来没用过useLayoutEffect,就没答上来。但是看名字应该是跟布局相关的,而且跟useEffect会有类似的作用。

React 中,useEffectuseLayoutEffect 都是用于处理副作用的 Hooks,但它们的执行时机和对渲染流程的影响有显著区别。以下是两者的核心差异及使用场景:

公众号:Code程序人生,个人网站:https://creatorblog.cn

1. 执行时机

Hook 执行实际
useEffect 异步执行:在浏览器完成布局和绘制(Paint)后触发。
useLayoutEffect 同步执行:在 React 完成 DOM 更新后、浏览器绘制前触发,会阻塞浏览器渲染。

React 组件更新 → 计算 DOM 变更 → 更新 DOM → [useLayoutEffect 执行] → 浏览器绘制 → [useEffect 执行]

2. 对用户体验的影响

Hook 用户感知
useEffect 副作用可能稍后执行,用户可能先看到未更新的界面,再看到更新后的内容(短暂闪烁)。
useLayoutEffect 副作用在绘制前完成,用户直接看到最终结果,避免视觉不一致。

示例:修改 DOM 样式

// 使用 useEffect(可能闪烁)
useEffect(() => {
  const element = document.getElementById("my-element");
  element.style.color = "red"; // 浏览器可能先绘制默认颜色,再变红
}, []);

// 使用 useLayoutEffect(无闪烁)
useLayoutEffect(() => {
  const element = document.getElementById("my-element");
  element.style.color = "red"; // 在绘制前完成修改
}, []);

3. 适用场景

Hook 典型场景
useEffect 数据获取(API 请求)/ 订阅事件(如 WebSocket) / 不需要同步 DOM 的操作
useLayoutEffect 测量 DOM 元素尺寸/位置(如动态调整布局) / 同步修改 DOM 样式以避免闪烁

示例:测量元素尺寸

useLayoutEffect(() => {
  const element = document.getElementById("my-element");
  const width = element.offsetWidth;
  setElementWidth(width); // 在绘制前获取并更新尺寸
}, []);

4. 性能影响

  • useEffect

异步执行,不会阻塞渲染,适合大多数场景,尤其是耗时操作(如网络请求)。

  • useLayoutEffect

同步执行,若副作用逻辑复杂可能导致渲染延迟,需谨慎使用。

5. 服务端渲染(SSR)

  • useEffect

无此问题,适合 SSR 环境。

  • useLayoutEffect

在服务端渲染时,React 会发出警告(因为其逻辑无法在服务端执行),需替换为 useEffect 或在客户端渲染后执行。

6. 代码示例对比

场景:点击按钮后动态调整元素高度

// 使用 useEffect(可能闪烁)
function Component() {
  const [height, setHeight] = useState(0);
  const ref = useRef();

  useEffect(() => {
    ref.current.style.height = "100px"; // 可能先渲染默认高度,再调整
  }, []);

  return <div ref={ref}>Height: {height}px</div>;
}

// 使用 useLayoutEffect(无闪烁)
function Component() {
  const [height, setHeight] = useState(0);
  const ref = useRef();

  useLayoutEffect(() => {
    ref.current.style.height = "100px"; // 在绘制前完成调整
  }, []);

  return <div ref={ref}>Height: {height}px</div>;
}

总结

维度 useEffect useLayoutEffect
执行时机 异步(绘制后) 同步(绘制前)
用户体验 可能闪烁 无闪烁
性能影响 可能阻塞渲染
适用场景 数据获取、订阅事件等异步操作 同步 DOM 操作(测量、调整样式)
SSR 兼容性 兼容 需特殊处理
  • 优先使用 useEffect
  • 仅在需要同步操作 DOM 或避免视觉不一致时使用 useLayoutEffect

你可能感兴趣的:(前端,面试,react,react.js,前端,面试)