Skip to content

fix(scroll): read initialScrollIndex offset after layout recompute#2133

Merged
naqvitalha merged 2 commits intomainfrom
fix/issue-1797-initial-scroll-index-overlap
Mar 4, 2026
Merged

fix(scroll): read initialScrollIndex offset after layout recompute#2133
naqvitalha merged 2 commits intomainfrom
fix/issue-1797-initial-scroll-index-overlap

Conversation

@naqvitalha
Copy link
Collaborator

Description

When initialScrollIndex is set and items have highly variable heights, items would overlap or the screen would appear blank. The root cause was in applyInitialScrollAdjustment() — the scroll offset for the target item was captured before recomputeLayouts(0, initialScrollIndex) ran. The recompute re-estimates unmeasured items with updated average heights (which shift as real measurements come in), changing the target item's y position. The stale offset created a mismatch between the EngagedIndicesTracker's scroll position and actual item positions, causing the wrong items (or none) to be rendered during progressive rendering.

The fix moves the offset read to after the recompute so the scroll offset always reflects the target item's actual position. Also fixes a minor operator precedence issue in the nullish coalescing fallback (initialItemOffset ?? 0 + this.firstItemOffset was evaluated as initialItemOffset ?? (0 + this.firstItemOffset)).

Fixes #1797

Reviewers' hat-rack 🎩

  • The core change is a single method in RecyclerViewManager.ts — focus on whether reading the offset after recomputeLayouts is always correct, including for the else branch (no initialScrollIndex).
  • Consider edge cases: horizontal lists, lists with ListHeaderComponent (non-zero firstItemOffset), and maintainVisibleContentPosition.startRenderingFromBottom.

Test plan

  • Unit tests pass (yarn test — 183 tests)
  • Type check passes (yarn type-check)
  • Lint passes (yarn lint)
  • Verified on iOS simulator — repro screen with 200 items (heights 40-500px) and initialScrollIndex=50 now correctly starts at Item 50
  • No regressions on Grid (initialScrollIndex=25) or HorizontalList (initialScrollIndex=2)
  • Scrolling up/down from the initial position renders all items without overlap or blank space

In applyInitialScrollAdjustment(), the scroll offset for the target
initialScrollIndex item was read before recomputeLayouts() ran. The
recompute re-estimates unmeasured items with updated average heights,
which shifts the target item's y position. The stale offset caused a
mismatch between the EngagedIndicesTracker's scroll position and the
actual item positions, resulting in blank screens or overlapping items
when initialScrollIndex was set with variable-height items.

Move the offset read to after recomputeLayouts() so the scroll offset
always reflects the target item's actual position. Also fixes a minor
operator precedence issue in the nullish coalescing fallback.

Includes a fixture repro screen (OverlapRepro) with 200 variable-height
items (40-500px) and initialScrollIndex=50.

Fixes #1797
@naqvitalha naqvitalha requested a review from tmgsca March 4, 2026 18:03
@naqvitalha naqvitalha force-pushed the fix/issue-1797-initial-scroll-index-overlap branch from 7312445 to 9c199f6 Compare March 4, 2026 18:18
@naqvitalha naqvitalha enabled auto-merge (squash) March 4, 2026 18:18
@naqvitalha naqvitalha merged commit 348c9ea into main Mar 4, 2026
11 checks passed
@naqvitalha naqvitalha deleted the fix/issue-1797-initial-scroll-index-overlap branch March 4, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Items overlap in FlashList v2

2 participants