Skip to content

Instantly share code, notes, and snippets.

@burdiuz
Last active November 1, 2021 15:15
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 burdiuz/9d88b6960552bea7ce5070c0d9549f77 to your computer and use it in GitHub Desktop.
Save burdiuz/9d88b6960552bea7ce5070c0d9549f77 to your computer and use it in GitHub Desktop.
React hook that watches for updates and returns element size.

@actualwave/use-element-size

React hook that watches for changes in element size using ResizeObserver and reports updates forcing component to render. There are two hooks in this package

  • useResizeObserver(handlerFn, elementRef) -- Calls handlerFn() when element size changed with instance of DOMRectReadOnly.
  • useElementSize(elementRef, reinitInEffect = true) -- Returns element size or null if elementRef.current does not contain reference to HTMLElement. reinitInEffect forces immediate re-render to apply element sizes, expected to have a valid reference at the time of re-render.

Example on codesandbox.io.

import { MutableRefObject } from '@types/react';
export declare const getElementDimensions = (el: HTMLElement) => { width: number, height: number };
export declare const useResizeObserver = (
handler: (list: DOMRectReadOnly) => void,
elRef: MutableRefObject<HTMLElement>
) => void;
export declare const useElementSize = (
elRef: MutableRefObject<HTMLElement>,
reinitInEffect?: boolean
) => { width: number, height: number } | null;
import { useState, useMemo, useEffect, useCallback } from 'react';
const getSizeOnly = ({ width, height }) => ({ width, height });
export const getElementDimensions = (el) => {
if (!el) {
return { width: 0, height: 0 };
}
return getSizeOnly(el.getBoundingClientRect());
};
export const useResizeObserver = (handler, elRef) => {
const observer = useMemo(() => {
if (!elRef.current) {
return null;
}
return new ResizeObserver(handler);
}, [handler, elRef.current]);
useEffect(() => {
if (!observer) {
return;
}
observer.observe(elRef.current);
return () => observer.disconnect();
}, [observer, elRef.current]);
};
export const useElementSize = (elRef, reinitInEffect = true) => {
let [size, setSize] = useState(null);
const handler = useCallback(
([{ borderBox, contentRect }]) => {
let size;
if (contentRect) {
size = getSizeOnly(contentRect);
} else {
size = borderBox.reduce(
({ width, height }, { inlineSize, blockSize }) => ({
width: width + inlineSize,
height: height > blockSize ? height : blockSize
}),
{ width: 0, height: 0 }
);
}
setSize(size);
},
[setSize]
);
useResizeObserver(handler, elRef);
useEffect(() => {
if (reinitInEffect) {
setSize(getElementDimensions(elRef.current));
}
}, []);
return size;
};
{
"name": "@actualwave/use-element-size",
"version": "0.0.1",
"description": "React hook that watches for updates and returns element size.",
"main": "index.js",
"module": "index.js",
"types": "index.d.ts",
"keywords": [
"react",
"element",
"size",
"resize",
"event",
"hook"
],
"peerDependencies": {
"react": ">=16.8.0",
"@types/react": ">=16.8.0"
},
"homepage": "https://gist.github.com/burdiuz/9d88b6960552bea7ce5070c0d9549f77",
"bugs": {
"url": "https://gist.github.com/burdiuz/9d88b6960552bea7ce5070c0d9549f77",
"email": "burdiuz@gmail.com"
},
"license": "MIT",
"author": "Oleg Galaburda <burdiuz@gmail.com> (http://actualwave.com/)"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment