Skip to content

Instantly share code, notes, and snippets.

@sujinleeme
Forked from morajabi/useRect.js
Last active March 21, 2024 15:27
Show Gist options
  • Save sujinleeme/c063b46bb78d97266bf37744d5f17223 to your computer and use it in GitHub Desktop.
Save sujinleeme/c063b46bb78d97266bf37744d5f17223 to your computer and use it in GitHub Desktop.
useRect — getBoundingClientRect() React Hook with resize handler (TypeScript)
// Require to install a package from npm with ResizeObserver typings.
// yarn --dev @types/resize-observer-browser
import { useCallback, useLayoutEffect, useRef, useState } from "react";
import ResizeObserver from 'resize-observer-polyfill'
type RectResult = {
bottom: number;
height: number;
left: number;
right: number;
top: number;
width: number;
} | null;
const getRect = (element: HTMLElement | null): RectResult | null => {
if (!element) return null;
return element.getBoundingClientRect();
};
export const useRect = (): [
RectResult,
React.MutableRefObject<HTMLDivElement | null>
] => {
const ref = useRef<HTMLDivElement | null>(null);
const current = ref.current || null;
const [rect, setRect] = useState(getRect(current));
const handleResize = useCallback(() => {
if (!ref.current) return;
// Update client rect
setRect(getRect(ref.current));
}, [ref]);
useLayoutEffect(() => {
const element = ref.current;
if (!element) return;
handleResize();
if (typeof ResizeObserver === "function") {
let resizeObserver: ResizeObserver | null = new ResizeObserver(() =>
handleResize()
);
resizeObserver.observe(element);
return () => {
if (!resizeObserver) return;
resizeObserver.disconnect();
resizeObserver = null;
};
}
// set resize listener
window.addEventListener("resize", handleResize);
// remove resize listener
return () => window.removeEventListener("resize", handleResize);
}, [handleResize]);
return [rect, ref];
};
@SlevinHertz
Copy link

Very good, working nice and clean, Thanks!

@lethib
Copy link

lethib commented May 28, 2023

Thanks a lot for that ! 🙏🏽

For those wondering about this hook utilisation, just link the ref provided by the hook to your HTMLDivElement. You can then access the dimension data in the rect object:

export const Foo = () => {
  const [barRect, barRef] = useRect()
  return (
    <div ref={barRef}>
      {barRect?.height}
      {barRect?.width}
      ...
    </div>
  )
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment