在 React 中通过 getBoundingClientRect 接收元素的尺寸
Posted
技术标签:
【中文标题】在 React 中通过 getBoundingClientRect 接收元素的尺寸【英文标题】:Receive dimensions of element via getBoundingClientRect in React 【发布时间】:2020-03-27 07:14:55 【问题描述】:我想以可靠的方式找出 DOM 元素的尺寸。
我的考虑是为此使用 getBoundingClientRect。
const elementRef = useRef<htmlUListElement | null>(null);
const [dimensions, setDimensions] = useState<DOMRect | undefined>();
const element: HTMLUListElement | null = elementRef.current;
/**
* Update dimensions state.
*/
const updateDimensions = useCallback(() =>
if (!element) return;
setDimensions(element.getBoundingClientRect());
, [element, setDimensions]);
/**
* Effect hook to receive dimensions changes.
*/
useEffect(() =>
if (element)
updateDimensions();
, [element, updateDimensions]);
这种方法的问题在于 useEffect 仅对 elementRef.current 做出反应,而不对 rect 更改做出反应。显然浏览器中组件的绘制还没有完成,因为尺寸总是0。
如果我在 useEffect 之外做所有事情,那么它会起作用。在控制台中,我看到 0 的 2 倍值,然后是正确的尺寸。
使用useEffect:
useEffect 之外:
但是,我想将尺寸保存在状态中,为此我需要 useEffect。
如何使用 getBoundingClientRect 实现这一点,或者有其他方法吗?
解决方案
这不是自我反应的问题。这是离子 V5 反应中的一个错误。
通常你可以这样做:
https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node
但这里有个问题:
https://github.com/ionic-team/ionic/issues/19770
我的解决方案是使用:https://github.com/que-etc/resize-observer-polyfill
import RefCallback, useCallback, useState from 'react';
import ResizeObserver from 'resize-observer-polyfill';
export function useDimensions(): [RefCallback<HTMLElement | null>, DOMRect | undefined]
const [dimensions, setDimensions] = useState<DOMRect | undefined>();
const ref: RefCallback<HTMLElement | null> = useCallback((node: HTMLElement | null) =>
if (node)
setDimensions(node.getBoundingClientRect().toJSON());
const resizeObserver = new ResizeObserver((entries) =>
if (entries.length)
setDimensions(entries[0].target.getBoundingClientRect().toJSON());
);
resizeObserver.observe(node);
return () =>
resizeObserver.unobserve(node);
resizeObserver.disconnect();
;
, []);
return [ref, dimensions];
【问题讨论】:
【参考方案1】:您可以使用 callBackRef 来实现所需的行为:
import React, useCallback, useState from "react";
export default function App()
const [dimensions, setDimensions] = useState(null);
const callBackRef = useCallback(domNode =>
if (domNode)
setDimensions(domNode.getBoundingClientRect());
, []);
return (
<div>
<h1 ref=callBackRef>Measure me</h1>
</div>
);
`
【讨论】:
通常是的,但我发现这是一个离子 V4 反应错误。我用解决方案更新了我的问题。【参考方案2】:如果性能是您关心的问题,那么除了使用 ResizeObserver 之外,我还会使用这个库来避免布局垃圾: https://github.com/ZeeCoder/use-resize-observer
请注意,由于以下特殊原因,它不使用 getBoundingClientReact(): https://gist.github.com/paulirish/5d52fb081b3570c81e3a
【讨论】:
以上是关于在 React 中通过 getBoundingClientRect 接收元素的尺寸的主要内容,如果未能解决你的问题,请参考以下文章
我们可以在 react native 中通过蓝牙连接到热敏收据打印机吗
在 React 中通过 axios 调用 API(使用自签名证书)时出现 CORS 问题
在后台从 React 组件制作 HTML 字符串,如何在另一个 React 组件中通过危险的SetInnerHTML 使用该字符串