react-responsive-pagination
Version:
React component for responsive pagination
46 lines (45 loc) • 1.84 kB
JavaScript
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;
}