Using the Resize Observer in Javascript

Unlike window, DOM elements don't have a resize event that you can attach an event listener on. To listen to resize events on a DOM element you need to use the ResizeObserver API:

const myElement = document.querySelector('.myElement');

// ๐Ÿ‘‡ Callback runs when any of the observed elements is resized
const resizeObserver = new ResizeObserver((entries) => {
  // You can iterate all of the element entries observed
  for (const entry of entries) {
    // Do something on resize, access the element on `entry.target`
  }
});

// ๐Ÿ‘‡ Listen to resize events on the element with `myElement` class
resizeObserver.observe(myElement);

// Unobeserve the element to stop tracking its size
resizeObserver.unobserve(myElement);

// Or stop observing all elements
resizeObserve.disconnect();
Creating a resize observer in JavaScript.
  1. Create the resize observer with new ResizeObserver(...).
  2. Pass in the callback function to run when the observer elements are resized.
  3. Start tracking the element's size with the .observe(element) function.

Using the Resize Observer in React

The most common way to use resize observer in react is by using useEffect to start tracking an element's size when the component is mounted. Here's how to do it:

function MyComponent() {
  const elementRef = useRef<HTMLDivElement>(null)

  // Start observing the element when the component is mounted
  useEffect(() => {
    const element = elementRef?.current;

    if (!element) return;

    const observer = new ResizeObserver(() => {
      // ๐Ÿ‘‰ Do something when the element is resized
    });

    observer.observe(element);
    return () => {
      // Cleanup the observer by unobserving all elements
      observer.disconnect();
    };
  }, [])

  // ๐Ÿ‘‡ Assign the ref to the element you're observing
  return <div ref={elementRef}>...</div>
}
Basic ResizeObserver usage in React components with TypeScript.
  1. Create a ref object using the useRef hook and assign it to the element you want to observe.
  2. Call the useEffect hook in your React component with a callback function [] as the dependency array.
  3. Inside, create the resize observer using new ResizeObserver(...) pass it the handler function.
  4. Start tracking the element's size with a call to ResizeObserver.observe(element).
  5. Return the cleanup function from useEffect that calls ResizeObserver.disconnect() to stop tracking the element when the component is unmounted.

The useResizeObserver hook

If you need to use resize observers often, writing the above code can become cumbersome and repetitive. You can move it to a reusable hook that allows you to easily keep track of the element's dimensions:

import { useLayoutEffect, useRef } from 'react';

function useResizeObserver<T extends HTMLElement>(
  callback: (target: T, entry: ResizeObserverEntry) => void
) {
  const ref = useRef<T>(null)

  useLayoutEffect(() => {
    const element = ref?.current;

    if (!element) {
      return;
    }

    const observer = new ResizeObserver((entries) => {
      callback(element, entries[0]);
    });

    observer.observe(element);
    return () => {
      observer.disconnect();
    };
  }, [callback, ref]);

  return ref
}

export default useResizeObserver;
A reusable React hook for the ResizeObserver.

You can then use it like this:

import { useCallback } from "react";

function Example() {
  const onResize = useCallback((target: HTMLDivElement) => {
    // Handle the resize event
  }, []);

  const ref = useResizeObserver(onResize);

  return <div ref={ref}>...</div>;
}
Example usage of the useResizeObserver hook.

The onResize function must preserve its references between component re-renders, that's why we wrap it with the useCallback hook. Otherwise, the resize observer would be re-created on every re-render, which may lead to performance issues.

Conclusion

Using the resize observer in React is the same as using it in JavaScript, and you can use the useEffect hook to hook into the React component lifecycle, for instance, to start observing when the component is mounted.

There may be a case when you want to start observing when some event happens, e.g. a button is pressed. The important point is that the resize observer must keep the same reference between component re-renders.

To do that, you can assign the ResizeObserver instance to a ref object created with a call to useRef and access it on the .current property.

Here are the complete code examples you can copy and paste ๐Ÿ‘‡

twitter-code/src/tooltips at main ยท vincaslt/twitter-code
Code examples from my Twitter @VincasStonys. Contribute to vincaslt/twitter-code development by creating an account on GitHub.