Skip to content

Instantly share code, notes, and snippets.

@gabemeola
Created February 18, 2022 01:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gabemeola/f3f88074b146d7a3a6fc47682b9a6f9f to your computer and use it in GitHub Desktop.
Save gabemeola/f3f88074b146d7a3a6fc47682b9a6f9f to your computer and use it in GitHub Desktop.
Get dimensions of a HTML Element in React
import { useState, useCallback, useLayoutEffect, RefObject, useMemo } from 'react';
import debounce from 'debounce';
export type Dimensions = [number, number];
export default function useRefDimensions(ref: RefObject<HTMLElement>): Dimensions {
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
const computeDimensions = useCallback((elem: Element) => {
const rect = elem.getBoundingClientRect();
const width = rect.width;
const height = rect.height;
setWidth(width);
setHeight(height);
}, [])
// Observe is Element is resized
useLayoutEffect(() => {
const currentElem = ref.current;
if (currentElem == null) return;
const frameIDs: Array<number> = [];
const resizeObserver = new ResizeObserver(debounce((entries) => {
const entry = entries.pop();
const target = entry?.target;
if (target != null) {
const frameID = window.requestAnimationFrame(() => {
computeDimensions(target);
})
frameIDs.push(frameID);
}
}, 50));
resizeObserver.observe(currentElem);
// Clean up
return () => {
resizeObserver.disconnect()
frameIDs.forEach((frame) => {
window.cancelAnimationFrame(frame);
})
};
}, [computeDimensions, ref])
// Memo to prevent React from thinking this Array is
// a new reference every render causing an infinite loop.
return useMemo(() => [width, height], [height, width]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment