Find element size in React with the useDimensions hook

Trying to find the size of an element in React can be quite annoying, especially if you want to keep track of any changes in size. The custom useDimensions hook should hopefully make this task much easier!

Usually keeping track of a div in vanilla Javascript is fairly easy: just keep track of any changes to the size of the window and check the size of the div whenever you need to.

This is complicated a bit by React as you actually need to be able to understand a couple of hooks before you can find the height and width of an element and keep track of it during window changes.

Here is a custom hook that I've got a lot of use out of in a variety of projects. Take a look at this simplification:

Move the divider between code and preview to see the hook in action!

How to the hook works

The code is fairly simple but let's go through it and break it down.

const [height, setHeight] = useState(0);
const [width, setWidth] = useState(0);

// The following measures the size of the div and listens to changes
const targetRef = useRef();
const RESET_TIMEOUT = 100;

const div_dimensions = () => {
  setHeight(targetRef.current.offsetHeight);
  setWidth(targetRef.current.offsetWidth);
};

This should be fairly easy to understand if you have a basic knowledge of React and Javascript.

height and width are our two states. We use these to keep track of both height and width.

targetRef is the useRef hook we will assign to a DOM element. Refs are usually useful for any kind of DOM manipulation, this time is no different.

div_dimensions will be launched every time we want to set our width and height values.

useLayoutEffect(() => {
  div_dimensions();
}, []);

If you haven't been using React for long you may not have come across useLayoutEffect yet. Its functionality is actually pretty simple. It works exactly like the useEffect hook, but runs after DOM mutations. This will ensure our layout has finished shifting before we set width and height.

const debouncedDimensions = debounce(div_dimensions, RESET_TIMEOUT);

useEffect(() => {
  window.addEventListener("resize", debouncedDimensions);
  return () => {
    window.removeEventListener("resize", debouncedDimensions);
  };
});

In this useEffect we're simply adding (and then removing for performance reasons) event listeners for window resize events.

Take note of debouncedDimensions. Here we use Lodash's debounce implementation. Debounce makes sure we don't set width and height on every frame, but only once every 100ms (which we set with RESET_TIMEOUT).

That's all!

This is probably one of the custom hooks I use the most during my day-to-day programming. Let me know how you put it to use!