UNPKG

react-responsive-pagination

Version:
46 lines (45 loc) 1.84 kB
import { useCallback, useEffect, useRef, useState } from 'react'; import { getContentWidth } from '../helpers/style.js'; import { useIsomorphicLayoutEffect } from '../helpers/react.js'; import { flushSync } from 'react-dom'; export function useContentWidth(element) { const [width, setWidth] = useState(); const widthRef = useRef(undefined); const syncWidth = useCallback(() => { const newWidth = element ? getContentWidth(element) : undefined; if (widthRef.current !== newWidth) { widthRef.current = newWidth; setWidth(newWidth); } }, [element]); useIsomorphicLayoutEffect(syncWidth); useEffect(() => { if (!element) return; const resizeObserver = new ResizeObserver(withResizeLoopDetection(() => flushSync(syncWidth))); resizeObserver.observe(element); return () => { resizeObserver.disconnect(); }; }, [element, syncWidth]); return width; } function withResizeLoopDetection(callback) { return (entries, resizeObserver) => { const elements = entries.map(entry => entry.target); const rectsBefore = elements.map(element => element.getBoundingClientRect()); callback(); const rectsAfter = elements.map(element => element.getBoundingClientRect()); const changedElements = elements.filter((_, i) => !areRectSizesEqual(rectsBefore[i], rectsAfter[i])); changedElements.forEach(element => unobserveUntilNextFrame(element, resizeObserver)); }; } function unobserveUntilNextFrame(element, resizeObserver) { resizeObserver.unobserve(element); requestAnimationFrame(() => { resizeObserver.observe(element); }); } function areRectSizesEqual(rect1, rect2) { return rect1.width === rect2.width && rect1.height === rect2.height; }