From 75730fa8866074cc2ca580b355962480ea3b8398 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sun, 31 May 2026 06:32:37 -0700 Subject: [PATCH] perf: move file search cleanup to root ref (#4163) --- .../src/components/right-sidebar/Search.tsx | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/renderer/src/components/right-sidebar/Search.tsx b/src/renderer/src/components/right-sidebar/Search.tsx index 82934cfc46c..8d20625d7b8 100644 --- a/src/renderer/src/components/right-sidebar/Search.tsx +++ b/src/renderer/src/components/right-sidebar/Search.tsx @@ -47,6 +47,8 @@ export default function Search(): React.JSX.Element { const revealRafRef = useRef(null) const revealInnerRafRef = useRef(null) const seededInputSelectionRafRef = useRef(null) + const cleanupSearchPanelRef = useRef<() => void>(() => {}) + const previousCleanupSearchPanelRef = useRef<(() => void) | null>(null) const includeInputRef = useRef(null) const excludeInputRef = useRef(null) @@ -115,16 +117,32 @@ export default function Search(): React.JSX.Element { } }, []) - // Cleanup debounce timer on unmount - useEffect(() => { - return () => { - cancelPendingSearch() - cancelSeededInputSelectionFrame() - cancelRevealFrame(revealRafRef) - cancelRevealFrame(revealInnerRafRef) - } + const cleanupCurrentSearchPanel = useCallback(() => { + cancelPendingSearch() + cancelSeededInputSelectionFrame() + cancelRevealFrame(revealRafRef) + cancelRevealFrame(revealInnerRafRef) }, [cancelPendingSearch, cancelSeededInputSelectionFrame]) + cleanupSearchPanelRef.current = cleanupCurrentSearchPanel + + useEffect(() => { + const previousCleanup = previousCleanupSearchPanelRef.current + previousCleanupSearchPanelRef.current = cleanupCurrentSearchPanel + if (previousCleanup && previousCleanup !== cleanupCurrentSearchPanel) { + previousCleanup() + } + }, [cleanupCurrentSearchPanel]) + + const setSearchPanelRef = useCallback((node: HTMLDivElement | null): void => { + if (node !== null) { + return + } + // Why: debounce, seeded focus, and reveal frames are scoped to this panel + // owner; clearing them from a stable root ref avoids a cleanup-only Effect. + cleanupSearchPanelRef.current() + }, []) + useEffect(() => { if (!worktreePath) { cancelPendingSearch() @@ -326,7 +344,7 @@ export default function Search(): React.JSX.Element { } return ( -
+