use*_*782 5 javascript browser reactjs react-hooks
我正在关注新的 React 文档中的钩子工具提示示例。useLayoutEffect根据他们的解释,我假设以下是事情的执行顺序:
React render() --> 协调 --> 如果 virtual dom 改变则更新 DOM --> DOM 更新完成 --> useLayoutEffect 被执行 --> broswer 绘制并触发某种 LayoutPaint 事件 --> useEffect 被触发
为了验证这一点,我将文档示例的 tooltip.js 文件中的useLayouteffecthook 与hook 交换了。useEffect
我放置了一些for循环来减慢useEffect钩子的执行速度。现在,当您加载修改后的示例并将鼠标移到三个按钮中的任何一个时,您将看到第一次使用工具提示在错误的位置进行绘制,然后 useEffect 需要 1-2 秒,然后您将看到工具提示在正确的位置进行另一次重新绘制。到目前为止一切都很好,但现在任何以后的鼠标悬停在同一个按钮上,您都会看到错误位置绘制等待 useEffect 完成,然后正确位置绘制在几毫秒内发生。
所以我有两个问题:
为什么后来的鼠标悬停会导致useEffect渲染阻塞?
React 如何确保useLayoutEffect阻止浏览器绘制发生,如果useLayoutEffect提到其中的任何状态更新,则触发另一个渲染->重绘,同时完全不允许发生先前的浏览器绘制。在我们的例子中,-60px处的工具提示根本没有被绘制。
该useEffect钩子通常不会阻塞渲染。但是,如果钩子内发生大量计算,则可能会导致显着的延迟,并且看起来好像阻塞了渲染。在您的情况下, 中的嵌套循环useEffect可能会导致此行为。
useLayoutEffect在 DOM 突变之后、浏览器绘制之前同步运行。如果状态更新发生在 内useLayoutEffect,React 会在useLayoutEffect完成后立即刷新此状态更新,从而在浏览器有机会绘制之前导致同步重新渲染。这可以防止绘制中间状态(例如 -60px 处的工具提示)。
import { useRef, useEffect, useState } from "react";
import { createPortal } from "react-dom";
import TooltipContainer from "./TooltipContainer.js";
export default function Tooltip({ children, targetRect }) {
const ref = useRef(null);
const [tooltipHeight, setTooltipHeight] = useState(60);
useEffect(() => {
if (ref.current) {
const { height } = ref.current.getBoundingClientRect();
setTooltipHeight(height);
}
}, [targetRect]); // Re-run this effect when targetRect changes
let tooltipX = 0;
let tooltipY = 0;
if (targetRect !== null) {
tooltipX = targetRect.left;
tooltipY = targetRect.top - tooltipHeight;
if (tooltipY < 0) {
// It doesn't fit above, so place below.
tooltipY = targetRect.bottom;
}
}
return createPortal(
<TooltipContainer x={tooltipX} y={tooltipY} contentRef={ref}>
{children}
</TooltipContainer>,
document.body
);
}Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
330 次 |
| 最近记录: |