retry autofit calculation to prevent zero value on initial render and memoization

This commit is contained in:
jeffvli
2026-01-22 02:53:25 -08:00
parent 3a5d701195
commit b45594515e
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { useLayoutEffect } from 'react';
interface UseContainerWidthTrackingProps {
autoFitColumns: boolean;
@@ -18,14 +18,58 @@ export const useContainerWidthTracking = ({
setCenterContainerWidth,
setTotalContainerWidth,
}: UseContainerWidthTrackingProps) => {
const createWidthUpdater = (
el: HTMLDivElement,
setWidth: (width: number) => void,
opts?: { maxRafRetries?: number },
) => {
const maxRafRetries = opts?.maxRafRetries ?? 10;
let rafId: null | number = null;
const cancel = () => {
if (rafId !== null) cancelAnimationFrame(rafId);
rafId = null;
};
const updateWidth = () => {
const measured = el.clientWidth || 0;
if (measured > 0) {
cancel();
setWidth(measured);
return;
}
// Some layouts can report 0 on first paint
// Retry a few frames to catch the first non-zero measurement
cancel();
let attempts = 0;
const retry = () => {
const next = el.clientWidth || 0;
if (next > 0) {
rafId = null;
setWidth(next);
return;
}
attempts++;
if (attempts < maxRafRetries) {
rafId = requestAnimationFrame(retry);
} else {
rafId = null;
setWidth(0);
}
};
rafId = requestAnimationFrame(retry);
};
return { cancel, updateWidth };
};
// Track center container width (for column distribution)
useEffect(() => {
useLayoutEffect(() => {
const el = rowRef.current;
if (!el) return;
const updateWidth = () => {
setCenterContainerWidth(el.clientWidth || 0);
};
const { cancel, updateWidth } = createWidthUpdater(el, setCenterContainerWidth);
updateWidth();
@@ -45,18 +89,17 @@ export const useContainerWidthTracking = ({
if (debounceTimeout) {
clearTimeout(debounceTimeout);
}
cancel();
resizeObserver.disconnect();
};
}, [rowRef, setCenterContainerWidth]);
// Track total container width for autoFitColumns
useEffect(() => {
useLayoutEffect(() => {
const el = containerRef.current;
if (!el || !autoFitColumns) return;
const updateWidth = () => {
setTotalContainerWidth(el.clientWidth || 0);
};
const { cancel, updateWidth } = createWidthUpdater(el, setTotalContainerWidth);
updateWidth();
@@ -76,6 +119,7 @@ export const useContainerWidthTracking = ({
if (debounceTimeout) {
clearTimeout(debounceTimeout);
}
cancel();
resizeObserver.disconnect();
};
}, [autoFitColumns, containerRef, setTotalContainerWidth]);