From dac53d8295ee35e606e761af83803345286f07df Mon Sep 17 00:00:00 2001 From: Harshit Singh Bhandari Date: Fri, 12 Jun 2026 18:24:02 +0530 Subject: [PATCH] fix(renderer): stabilize onResize ref to prevent rrp constraint race (#193) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wrap handleInspectorResize in useCallback so rrp v4's panel registration useLayoutEffect (which includes onResize in its dep array) does not de-register/re-register the inspector panel on every render. Without this, any re-render of SessionView (workspace data arriving, daemon status change, etc.) created a new handleInspectorResize reference, triggering rrp's cleanup → re-registration cycle. With React 19's automatic batching, this window reliably overlapped with the expand()/collapse() useEffect on initial sidebar click, causing the "Panel constraints not found for Panel inspector" throw that tore down the session view. Closes #185. --- .../src/renderer/components/SessionView.tsx | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/frontend/src/renderer/components/SessionView.tsx b/frontend/src/renderer/components/SessionView.tsx index 8f19ad399..56fc797c3 100644 --- a/frontend/src/renderer/components/SessionView.tsx +++ b/frontend/src/renderer/components/SessionView.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef } from "react"; +import { useCallback, useEffect, useRef } from "react"; import type { PanelImperativeHandle, PanelSize } from "react-resizable-panels"; import { CenterPane } from "./CenterPane"; import { SessionInspector } from "./SessionInspector"; @@ -116,16 +116,23 @@ export function SessionView({ sessionId }: SessionViewProps) { // data-separator="active" only during a pointer drag — the same hook the // transition-suppressing CSS keys on, so drag writes are never transition // frames. - const handleInspectorResize = (size: PanelSize) => { - if (inspectorSeparatorRef.current?.getAttribute("data-separator") !== "active") return; - const open = useUiStore.getState().isInspectorOpen; - if (size.asPercentage > 0) { - window.localStorage?.setItem(inspectorSplitStorageKey, String(size.asPercentage)); - if (!open) toggleInspector(); - } else if (open) { - toggleInspector(); - } - }; + // Also wrapped in useCallback: rrp v4's panel registration useLayoutEffect + // includes onResize in its dep array, so an unstable reference would + // de-register/re-register the inspector panel on every render and race + // with the expand()/collapse() effect above. + const handleInspectorResize = useCallback( + (size: PanelSize) => { + if (inspectorSeparatorRef.current?.getAttribute("data-separator") !== "active") return; + const open = useUiStore.getState().isInspectorOpen; + if (size.asPercentage > 0) { + window.localStorage?.setItem(inspectorSplitStorageKey, String(size.asPercentage)); + if (!open) toggleInspector(); + } else if (open) { + toggleInspector(); + } + }, + [toggleInspector], + ); if (!session && !workspaceQuery.isLoading) { return (