react ResizeObserver Пример получения ширины элемента при изменении его размера на странице. Не только при измении окна браузера

Далее приводится код, который позволяет отследить изменения размеров html dom элемента, не только когда изменяется размер окна браузера, но и когда изменяются размеры других элементов на странице (а наш отслеживаемый элемент растягивается или сжимается из-за этого).

Код написан для для отслеживания ширины элемента, но можно получить и другие значения с помощью ResizeObserver.

Базовый пример

Простейший пример (тайпскрипт, но с JS будет по аналогии):

import { useStyles } from "./styles";
import { useState, useEffect, useRef, memo } from "react";

export type PropsType = any;

export function ControledElement(props: PropsType) {
  const ref: any = useRef();

  const classes = useStyles();
  console.log("ControledElement!");

  const observer = useRef(
    new ResizeObserver((entries) => {
      const { width } = entries[0].contentRect;
      console.log('current width: ', width);
    })
  );

  useEffect(() => {
    observer.current.observe(ref.current);
  }, 
  [ref, observer]);

  return (
    <div ref={ref} className={classes.right}>
      Right
    </div>
  );
}

export const MemoizedControledElement = memo(ControledElement);

-- специально экспортируем еще и мемоизированную версию, т.к. в случае её использования при изменеии размера другого блока (влияющего на размер нашего) ререндера не произойдет и вот тут-то нам особенно актуально использовать именно подход с ResizeObserver

Пользовательский хук для ResizeObserver

Пример вышем можно переписать с использованием хука (этот хук можно потом применить в любом другом компоненте, переиспользуя код):

import { useStyles } from "./styles";
import { useState, useEffect, useRef, memo } from "react";

export type PropsType = any;


// custom hook for ResizeObserver
const useElementWidth = () => {

    const ref: any = useRef();
    const [width, setWidth] = useState<null | number>(null);

    const observer = useRef(
      new ResizeObserver((entries) => {
        const { width } = entries[0].contentRect;
        setWidth(width);
      })
    );
  
    useEffect(() => {
      observer.current.observe(ref.current);
    }, 
    [ref, observer]);

    return [ref, width];
}

export function ControledElement(props: PropsType) {

  const classes = useStyles();
  const [ref, width] =  useElementWidth();
  console.log('current width: ', width);

  return (
    <div ref={ref} className={classes.right}>
      Right
    </div>
  );
}

export const MemoizedControledElement = memo(ControledElement);

Сделано на базе идеи (но там менее конкртные фрагменты кода): https://blog.sethcorker.com/resize-obser...