fix: re-measure virtualizer items when async card content loads (#605)

PR/issue data arrives after worktree cards mount, changing their height.
The virtualizer's ResizeObserver can miss the resize during React's
batched rendering, leaving stale measurements and overlapping cards.

Add a useLayoutEffect that re-measures all cached elements when the
PR or issue cache grows, ensuring positions are corrected before paint.
This commit is contained in:
Jinjing 2026-04-13 18:36:01 -07:00 committed by GitHub
parent c25b711684
commit 60a72f2b29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 19 additions and 0 deletions

View File

@ -371,6 +371,25 @@ const WorktreeList = React.memo(function WorktreeList() {
clearPendingRevealWorktreeId
])
// ── Async content re-measurement ──────────────────────────────
// PR and issue data arrive asynchronously after cards mount. When a
// card gains an issue/PR row its height changes, and the virtualizer's
// ResizeObserver should reposition subsequent items. In practice the
// observer can miss the resize when it coincides with React's batched
// rendering — leaving stale measurements and overlapping cards.
//
// Why useLayoutEffect: runs after React commits the new DOM (cards now
// include the issue row) but before the browser paints, so the user
// never sees a frame of overlap.
const prCacheLen = useAppStore((s) => Object.keys(s.prCache).length)
const issueCacheLen = useAppStore((s) => Object.keys(s.issueCache).length)
useLayoutEffect(() => {
virtualizer.elementsCache.forEach((element) => {
virtualizer.measureElement(element)
})
}, [prCacheLen, issueCacheLen, virtualizer])
const navigateWorktree = useCallback(
(direction: 'up' | 'down') => {
const worktreeRows = rows.filter(