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

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

问题描述

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

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

我的考虑是为此使用getBoundingClientRect.

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

此方法的问题在于useEffect仅对elementRef.current作出反应,而对rect更改不作出反应.显然,浏览器中组件的绘制尚未完成,因为尺寸始终为0.

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.

如果我在useEffect之外进行全部操作,那么它将起作用.在控制台中,我看到值为0的2倍值,然后是正确的尺寸.

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.

具有useEffect:

With useEffect:

使用以外的效果:

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

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

如何使用getBoundingClientRect实现此目的,或者还有另一种方法可以做到这一点?

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

解决方案

这不是自我反应的问题.这是离子V5反应中的错误.

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

但这是一个问题:

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

我的解决方案是使用: https://github.com/que-etc/resize-observer-polyfill

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

推荐答案

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

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天全站免登陆