reactjs - 在浏览器有机会绘制之前,React 如何正确测量 useLayoutEffect Hook 中的 DOM 元素?

标签 reactjs

在官方 React 文档中,对于 useLayoutEffect ,其中提到:

The signature is identical to useEffect, but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.

此外,在 useLayoutEffect 中,我们能够在浏览器实际重新绘制之前读取更新的尺寸。

react 是如何做到这一点的?

最佳答案

所以@Marko 是对的。

浏览器渲染周期分为几个阶段,相关的阶段是:

  1. 样式 - 将 HTML 与 CSS 合并
  2. 布局 - 计算所有元素的大小和位置
  3. 油漆

Mozilla docs

useLayoutEffect 在布局之后、绘制之前运行

要实现这一点,您需要做的(或 React 所做的)就是在 DOM 树中添加或更改元素后同步运行 useLayoutEffect 函数。

除非您释放线程,否则浏览器无法运行绘画阶段。

如果您向浏览器询问元素的大小,它会同步运行布局阶段来给您答案。

这是一个片段和一个 sandbox演示这个想法:

const conatiner = document.getElementById("container");

function busyWait() {
  const array = new Array(100000).fill(Math.random());
  let sum = 0;
  array.forEach((val, index) => {
    const item = array.find((val, i) => i === index);
    sum = sum + item;
  });
  return sum;
}

function addElement() {
  const newElement = document.createElement("p");
  newElement.innerText =
    "this is a paragraph, browser need to measure it to know its size";

  if (conatiner) {
    conatiner.appendChild(newElement);
    console.log(
      "layout phase element size",
      JSON.stringify(newElement.getBoundingClientRect())
    );
    const sum = busyWait();
    console.log(sum);

    setTimeout(() => {
      console.log(
        "after paint element size",
        JSON.stringify(newElement.getBoundingClientRect())
      );
    }, 10);
  }
}

setTimeout(addElement, 100);
<div>
      we are going to test layout / replaint stages
      <div id="container" style="width: 200px;"></div>
</div>

  • 我添加一个新元素
  • 询问其尺寸
  • 记录它
  • 然后忙等待(不将线程释放给浏览器) => 您可以在日志中看到正确的大小,但在屏幕上看不到该元素

关于reactjs - 在浏览器有机会绘制之前,React 如何正确测量 useLayoutEffect Hook 中的 DOM 元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60769022/

相关文章:

jquery - React 组件使用 JQuery 查找 last-of-type 类

reactjs - react native 0.31 : Could not get BatchedBridge Error

javascript - 在 Eslint 配置文件中禁用报价规则

reactjs - 未找到模块 : Error: Can't resolve 'pnpapi' in '/app/node_modules/next/dist/lib'

reactjs - Ant Design & Webpack 不加载 css

reactjs - React 中的响应式设计

reactjs - ReactQuery - useInfiniteQuery 重新获取问题

reactjs - 超小屏幕上的居中按钮 Material-UI React 不起作用(justify-xs-center)

css - 是否可以在 ReactJS 中的表格单元格上设置 CSSTransitionGroup?

javascript - 单击按钮时如何模糊整个网页