mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-28 19:18:22 +03:00
fix: replace useResizeObserver with useLayoutEffect for reliable container width
useResizeObserver reads ref.current during render (before commit), so on first render ref.current is null, no observation starts, and containerWidth stays 0 if no subsequent re-render happens (e.g. page refresh with cached SWR data). useLayoutEffect runs after refs are committed, so ref.current is always the real DOM element. This fixes both the right-column overflow (no window.innerWidth fallback needed — width is always the actual container width) and the black screen on refresh (containerWidth is reliable before the first paint). https://claude.ai/code/session_01H1sqbcFmtwwsdNTJcJHJWd
This commit is contained in:
parent
5e40dbbcd2
commit
067fdb50e1
@ -28,7 +28,7 @@ import {
|
|||||||
VolumeState,
|
VolumeState,
|
||||||
} from "@/types/live";
|
} from "@/types/live";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
|
||||||
import { isEqual } from "lodash";
|
import { isEqual } from "lodash";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { isDesktop, isMobile } from "react-device-detect";
|
import { isDesktop, isMobile } from "react-device-detect";
|
||||||
@ -329,23 +329,25 @@ export default function DraggableGridLayout({
|
|||||||
|
|
||||||
const gridContainerRef = useRef<HTMLDivElement>(null);
|
const gridContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [{ width: containerWidth, height: containerHeight }] =
|
const [containerWidth, setContainerWidth] = useState(0);
|
||||||
useResizeObserver(gridContainerRef);
|
const [containerHeight, setContainerHeight] = useState(0);
|
||||||
|
|
||||||
// useResizeObserver reads ref.current at render time, so it may miss the
|
// useLayoutEffect reads ref.current after commit (refs are set before layout
|
||||||
// initial mount when ref.current is null (e.g. on page refresh with cached
|
// effects run), so this reliably fires before the first paint regardless of
|
||||||
// SWR data). Measure the container synchronously in useLayoutEffect as a
|
// whether SWR triggers subsequent re-renders or not.
|
||||||
// reliable seed value; containerWidth from ResizeObserver takes over once
|
|
||||||
// it fires.
|
|
||||||
const [initialWidth, setInitialWidth] = useState(0);
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (gridContainerRef.current) {
|
const el = gridContainerRef.current;
|
||||||
setInitialWidth(gridContainerRef.current.offsetWidth);
|
if (!el) return;
|
||||||
}
|
setContainerWidth(el.clientWidth);
|
||||||
|
setContainerHeight(el.clientHeight);
|
||||||
|
const ro = new ResizeObserver(([entry]) => {
|
||||||
|
setContainerWidth(entry.contentRect.width);
|
||||||
|
setContainerHeight(entry.contentRect.height);
|
||||||
|
});
|
||||||
|
ro.observe(el);
|
||||||
|
return () => ro.disconnect();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const effectiveWidth = containerWidth || initialWidth;
|
|
||||||
|
|
||||||
const scrollBarWidth = useMemo(() => {
|
const scrollBarWidth = useMemo(() => {
|
||||||
if (containerWidth && containerHeight && containerRef.current) {
|
if (containerWidth && containerHeight && containerRef.current) {
|
||||||
return (
|
return (
|
||||||
@ -356,8 +358,8 @@ export default function DraggableGridLayout({
|
|||||||
}, [containerRef, containerHeight, containerWidth]);
|
}, [containerRef, containerHeight, containerWidth]);
|
||||||
|
|
||||||
const availableWidth = useMemo(
|
const availableWidth = useMemo(
|
||||||
() => (scrollBarWidth ? effectiveWidth + scrollBarWidth : effectiveWidth),
|
() => (scrollBarWidth ? containerWidth + scrollBarWidth : containerWidth),
|
||||||
[effectiveWidth, scrollBarWidth],
|
[containerWidth, scrollBarWidth],
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasScrollbar = useMemo(() => {
|
const hasScrollbar = useMemo(() => {
|
||||||
@ -373,7 +375,7 @@ export default function DraggableGridLayout({
|
|||||||
// subtract container margin, 1 camera takes up at least 4 rows
|
// subtract container margin, 1 camera takes up at least 4 rows
|
||||||
// account for additional margin on bottom of each row
|
// account for additional margin on bottom of each row
|
||||||
return (
|
return (
|
||||||
((availableWidth || window.innerWidth) - 2 * marginValue) /
|
(availableWidth - 2 * marginValue) /
|
||||||
12 /
|
12 /
|
||||||
aspectRatio -
|
aspectRatio -
|
||||||
marginValue +
|
marginValue +
|
||||||
@ -724,7 +726,7 @@ export default function DraggableGridLayout({
|
|||||||
currentGroups={groups}
|
currentGroups={groups}
|
||||||
activeGroup={group}
|
activeGroup={group}
|
||||||
/>
|
/>
|
||||||
{effectiveWidth > 0 && <Responsive
|
{containerWidth > 0 && <Responsive
|
||||||
className="grid-layout"
|
className="grid-layout"
|
||||||
width={availableWidth}
|
width={availableWidth}
|
||||||
layouts={{
|
layouts={{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user