Skip to content

Instantly share code, notes, and snippets.

@rmdort
Created February 26, 2022 11:58
Show Gist options
  • Save rmdort/8507fbaa27a88b18c5e78d230376510f to your computer and use it in GitHub Desktop.
Save rmdort/8507fbaa27a88b18c5e78d230376510f to your computer and use it in GitHub Desktop.
use-resizer-observer hook
import { useRef, useLayoutEffect, useState, useCallback } from "react";
type HTMLOrSVGElement = HTMLElement | SVGElement;
export type RectReadOnly = {
readonly x: number;
readonly y: number;
readonly width: number;
readonly height: number;
readonly top: number;
readonly right: number;
readonly bottom: number;
readonly left: number;
[key: string]: number;
};
type Result<T> = [React.RefObject<T> | null | undefined, RectReadOnly];
export const useResizeObserver = <T extends HTMLOrSVGElement>(): Result<T> => {
const [observerEntry, setObserverEntry] = useState<RectReadOnly>({
left: 0,
top: 0,
width: 0,
height: 0,
bottom: 0,
right: 0,
x: 0,
y: 0,
});
const node = useRef<T>(null);
const observer = useRef<ResizeObserver>();
const disconnect = useCallback(() => observer.current?.disconnect(), []);
const observe = useCallback(() => {
observer.current = new ResizeObserver(([entry]) =>
setObserverEntry(entry.contentRect.toJSON())
);
if (node.current) observer.current.observe(node.current);
}, [node]);
useLayoutEffect(() => {
observe();
return () => disconnect();
}, [disconnect, observe]);
return [node, observerEntry];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment