在 React 中通过 getBoundingClientRect 接收元素的尺寸 [英] Receive dimensions of element via getBoundingClientRect in React

查看:53
本文介绍了在 React 中通过 getBoundingClientRect 接收元素的尺寸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想以可靠的方式找出 DOM 元素的尺寸.

我的考虑是为此使用 getBoundingClientRect.

 const elementRef = useRef();const 元素:HTMLUListElement |null = elementRef.current;/*** 更新维度状态.*/const updateDimensions = useCallback(() => {如果(!元素)返回;setDimensions(element.getBoundingClientRect());}, [元素, setDimensions]);/*** 效果挂钩接收尺寸变化.*/useEffect(() => {如果(元素){更新维度();}}, [元素, 更新维度]);

这种方法的问题是 useEffect 只对 elementRef.current 做出反应,而不对 rect 的变化做出反应.显然浏览器中组件的绘制还没有完成,因为尺寸总是0.

如果我在 useEffect 之外做整个事情,那么它就可以工作.在控制台中,我看到 2 倍的值为 0,然后是正确的尺寸.

使用useEffect:

useEffect 之外:

但是,我想在状态中保存尺寸,为此我需要 useEffect.

我如何使用 getBoundingClientRect 来实现这一点,或者还有其他方法可以做到这一点?

解决方案

这不是自我反应的问题.这是ionic V5 react的一个bug.

通常你可以这样做:

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';从'resize-observer-polyfill'导入ResizeObserver;导出函数 useDimensions(): [RefCallback, DOMRect |不明确的] {const [dimensions, setDimensions] = useState<DOMRect |未定义>();const ref: RefCallback= useCallback((节点:HTMLElement | null) => {如果(节点){setDimensions(node.getBoundingClientRect().toJSON());const resizeObserver = new ResizeObserver((entries) => {如果(条目.长度){setDimensions(entries[0].target.getBoundingClientRect().toJSON());}});resizeObserver.observe(节点);返回 () =>{resizeObserver.unobserve(节点);resizeObserver.disconnect();};}}, []);返回 [参考,尺寸];}

解决方案

您可以使用 callBackRef 来实现所需的行为:

import React, { useCallback, useState } from "react";导出默认函数 App() {const [dimensions, setDimensions] = useState(null);const callBackRef = useCallback(domNode => {如果(domNode){setDimensions(domNode.getBoundingClientRect());}}, []);返回 (<div><h1 ref={callBackRef}>测量我</h1>

);}`

I would like to find out the dimensions of a DOM element in a reliable way.

My consideration was to use getBoundingClientRect for this.

  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]);

The problem with this approach is that useEffect only reacts to elementRef.current and not to the rect changes. Apparently the drawing of the component in the browser is not finished yet, because the dimensions are always 0.

If I do the whole thing outside the useEffect then it works. In the console I see 2 times values with 0 and then the correct dimensions.

With useEffect:

Outside of useEffect:

However, I would like to save the dimensions in the state and for this I need the useEffect.

How can I achieve this with getBoundingClientRect or is there another way to do this?

SOLUTION

It was not a problem of react it self. It is a bug in ionic V5 react.

Normally you can do it in this way:

https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node

But here is an issue:

https://github.com/ionic-team/ionic/issues/19770

My solution is to use: 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];
}

解决方案

you can use a callBackRef to achieve desired behaviour:

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>
  );
}`

这篇关于在 React 中通过 getBoundingClientRect 接收元素的尺寸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆