From dd71917852d8f2154c052a55bb5efd6a913a079c Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sun, 31 May 2026 04:25:50 -0700 Subject: [PATCH] perf: move worktree reveal timer cleanup to ref (#4105) --- .../src/components/sidebar/WorktreeList.tsx | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/renderer/src/components/sidebar/WorktreeList.tsx b/src/renderer/src/components/sidebar/WorktreeList.tsx index 77e6e84f6..74582d30d 100644 --- a/src/renderer/src/components/sidebar/WorktreeList.tsx +++ b/src/renderer/src/components/sidebar/WorktreeList.tsx @@ -720,21 +720,28 @@ const VirtualizedWorktreeViewport = React.memo(function VirtualizedWorktreeViewp const worktreeNativeLatestPointRef = useRef(null) const pendingRevealRetryRef = useRef<{ worktreeId: string; count: number } | null>(null) const revealHighlightTimeoutRef = useRef(null) - const flashRevealedWorktree = useCallback((worktreeId: string) => { + const clearRevealHighlightTimeout = useCallback(() => { if (revealHighlightTimeoutRef.current !== null) { window.clearTimeout(revealHighlightTimeoutRef.current) + revealHighlightTimeoutRef.current = null } - // Why: remove before add restarts the CSS glow when the user repeatedly - // asks to reveal the same active workspace. - setHighlightedRevealWorktreeId(null) - window.requestAnimationFrame(() => { - setHighlightedRevealWorktreeId(worktreeId) - revealHighlightTimeoutRef.current = window.setTimeout(() => { - revealHighlightTimeoutRef.current = null - setHighlightedRevealWorktreeId(null) - }, 1500) - }) }, []) + const flashRevealedWorktree = useCallback( + (worktreeId: string) => { + clearRevealHighlightTimeout() + // Why: remove before add restarts the CSS glow when the user repeatedly + // asks to reveal the same active workspace. + setHighlightedRevealWorktreeId(null) + window.requestAnimationFrame(() => { + setHighlightedRevealWorktreeId(worktreeId) + revealHighlightTimeoutRef.current = window.setTimeout(() => { + revealHighlightTimeoutRef.current = null + setHighlightedRevealWorktreeId(null) + }, 1500) + }) + }, + [clearRevealHighlightTimeout] + ) const suppressWorktreeClickUntilRef = useRef(0) const hasProjectGroups = projectGroups.length > 0 const canReorderRepoHeaders = @@ -1445,14 +1452,6 @@ const VirtualizedWorktreeViewport = React.memo(function VirtualizedWorktreeViewp markScrollMovement() }, [markScrollMovement]) - useEffect(() => { - return () => { - if (revealHighlightTimeoutRef.current !== null) { - window.clearTimeout(revealHighlightTimeoutRef.current) - } - } - }, []) - const cancelWorktreePointerAutoscroll = useCallback(() => { if (worktreePointerAutoscrollFrameIdRef.current !== null) { window.cancelAnimationFrame(worktreePointerAutoscrollFrameIdRef.current) @@ -1497,13 +1496,14 @@ const VirtualizedWorktreeViewport = React.memo(function VirtualizedWorktreeViewp const setScrollRootRef = useCallback( (node: HTMLDivElement | null) => { if (node === null && scrollRef.current !== null) { - // Why: sidebar drag previews and autoscroll frames are tied to the - // scroll root surface; clear them before that DOM owner disappears. + // Why: sidebar drag previews, autoscroll frames, and reveal glow timers + // are tied to the scroll root surface; clear them before it disappears. + clearRevealHighlightTimeout() clearWorktreeDrag() } scrollRef.current = node }, - [clearWorktreeDrag] + [clearRevealHighlightTimeout, clearWorktreeDrag] ) const flushWorktreePointerDrag = useCallback(() => {