useLayoutEffect与页面渲染

文章讨论了React中的useLayoutEffect钩子函数的工作原理。它指出useLayoutEffect不是在渲染前执行,而是在布局阶段同步执行,允许访问最新的DOM。因此,即使testA大于0.5,代码仍然可以在useLayoutEffect中获取到redDiv的DOM元素,用于防止页面闪烁。同时,文章通过对比useLayoutEffect和快照更新的功能,强调了useLayoutEffect在更新UI时的同步特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提出一个问题:useLayoutEffect是渲染前执行的。那么下面的代码里,testA > 0.5时能获取到最新的dom吗?

分析:
首先点击了button ,testA变为大于0.5的数字,
此时进入useLayoutEffect,如果按照上述的理解,useLayoutEffect是渲染前执行的,
那么此时虽然 testA > 0.5 但是redDiv是还没来得及渲染出来呢!
就不能获取到真实dom。

先看下面代码:

function ChildFunction() {
  const [testA, setTestA] = useState(0);
  
  useLayoutEffect(() => {
    console.log('useLayoutEffect', testA);
    if (testA > 0.5) {
      setTestA(0.5);
    }
    const redDiv = document.querySelector('#redDiv');
    console.log('useLayoutEffect-----redDiv', redDiv?.offsetTop);
  }, [testA]);

  return (
    <div>
      ChildFunction 组件
      <br />
      <button
        type="button"
        onClick={() => {
          setTestA(Math.random() * 100);
        }}
      >
        click
      </button>
      {testA > 0.5 ? (
        <div
          id="redDiv"
          style={{
            backgroundColor: 'red',
            width: '300px',
            height: '300px',
            margin: '200px',
          }}
        ></div>
      ) : null}
    </div>
  );
}

输出:
在这里插入图片描述

如果按照大多数资料里的意思,useLayoutEffect 是渲染前执行的,怎么可能获取到 真实dom(id=redDiv 的div)呢?

原因:

先来理解页面渲染的步骤

首先我们得明白浏览器渲染的几个步骤 :

dom tree - cssom tree - 前2者合并 生成render tree - 布局 layout - 绘制(Paint)- 合成(Composite)

这里解释一下后3个概念
布局(Layout):浏览器根据渲染树中每个节点的大小、位置和样式等信息,计算出每个节点在屏幕上的精确位置和大小,并生成布局信息。
绘制(Paint):浏览器根据布局信息,使用图形库将每个节点绘制成图像,并填充颜色、渐变、阴影等效果。
合成(Composite):浏览器将所有绘制的图像按照正确的顺序合成到屏幕上。

useLayoutEffect 是在组件渲染过程中调用,在浏览器 layout 的时候同步执行的Hook。
这也就是useLayoutEffect名称的来源!
也就是说,useLayoutEffect可以同步地读取布局信息。可以理解为 useLayoutEffect执行的时机是真实dom已经准备好了,就是没画到页面上。

所以:不是渲染前调用,是渲染完成之前调用!!

useLayoutEffect的作用

简单说就是:在用户看到前,改变某个元素的位置,可防止闪烁。

普通情况下,使用useEffect人眼是看不出闪烁的。
下面的例子能明显看出,当有一些长任务阻塞渲染的时候,才会导致出现闪烁的问题。
但是,此时若使用了 useLayoutEffect 其实也会导致页面很久才能响应。所以此时应该:拆分长任务、或使用useTransition 来提高响应速度 同时 使用useLayoutEffect以防出现闪烁。

参考官网

描述

useLayoutEffect Vs 快照 Vs useEffect

代码如下,isClick 默认是 false
在这里插入图片描述
结果如下,getSnapShotBeforeUpdate是无法获取最新的dom元素的!!ref 跟 document.getxxx操作都是去获取真实dom!!
在这里插入图片描述
总结:

useEffect: 渲染完后,才执行。所以不阻塞渲染。能拿到最新的dom
useLayoutEffect: 渲染到layout后,执行。会阻塞渲染。能拿到最新的dom结构。
getSnapShotBeforeUpdate: render后,渲染前执行。不阻塞渲染。拿不到最新的dom,能拿到旧的dom。这个函数的目的就是去取旧的dom.

执行顺序:render方法 - getSnapShotBeforeUpdate - 渲(useLayoutEffect)染 - useEffect

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值