Stop the grid's window size from looping React into a crash

The grid read the window's size whenever React read its snapshot. React
re-reads the snapshot after every commit and re-renders if it changed, and
rendering the grid can change the window's size: on Windows, a window size
where the full-width grid gives the page a scrollbar shrinks clientWidth by
the scrollbar, and the narrower grid takes the scrollbar away again. That
went round until React gave up ("Maximum update depth exceeded", #185),
on load or on resizing to such a size.

The size is now measured only when the grid subscribes and on resize, and
the snapshot just returns it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Jordan EldredgeandClaude Opus 5.5 committed 2026-11-04 18:07:45 -08:00
1 parent e0ad6417cb
commit 165e55658c
1 file changed
+25 -7
@@ -178,14 +178,26 @@ const SORT_ICONS: Record<MuseumSort, typeof Star> = {
type WindowSize = { width: number; height: number; scrollbarWidth: number };
let windowSize: WindowSize | null = null;
function getWindowSize(): WindowSize {
// Measured when the grid subscribes and on resize, never while React reads the
// snapshot. Rendering the grid can change the window's size: if it gives the
// page a scrollbar that takes up room (Windows), clientWidth shrinks, the
// narrower grid can take it away again, and so on. React re-reads the snapshot
// after every commit and re-renders if it changed, so reading the size there
// went round that loop until React gave up ("Maximum update depth exceeded").
function measureWindowSize(): boolean {
const width = document.documentElement.clientWidth;
const height = document.documentElement.clientHeight;
if (windowSize?.width !== width || windowSize.height !== height) {
// Measured again with the size, as zooming changes both.
windowSize = { width, height, scrollbarWidth: measureScrollbarWidth() };
if (windowSize?.width === width && windowSize.height === height) {
return false;
}
return windowSize;
// Measured again with the size, as zooming changes both.
windowSize = { width, height, scrollbarWidth: measureScrollbarWidth() };
return true;
}
function getWindowSize(): WindowSize {
if (windowSize == null) measureWindowSize();
return windowSize!;
}
// The width of a vertical scrollbar, like the grid's. From rects rather than
@@ -205,8 +217,14 @@ function measureScrollbarWidth(): number {
}
function subscribeToResize(onChange: () => void): () => void {
window.addEventListener("resize", onChange);
return () => window.removeEventListener("resize", onChange);
// The window may have changed size since the grid was last shown. React
// checks the snapshot again once subscribed, so this needs no onChange.
measureWindowSize();
const onResize = () => {
if (measureWindowSize()) onChange();
};
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
}
function useMountedWindowSize(): WindowSize | null {