-
-
Save sujinleeme/c063b46bb78d97266bf37744d5f17223 to your computer and use it in GitHub Desktop.
useRect — getBoundingClientRect() React Hook with resize handler (TypeScript)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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]; | |
}; |
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
Very good, working nice and clean, Thanks!