Skip to content

fix(recyclerview): keep maintaining position when measurements push the anchor out of the rendered window - #2536

Open
neddtu wants to merge 1 commit into
Shopify:mainfrom
neddtu:fix/anchor-search-while-in-view
Open

neddtu wants to merge 1 commit into
Shopify:mainfrom
neddtu:fix/anchor-search-while-in-view

Conversation

@neddtu

@neddtu neddtu commented Oct 13, 2026

Copy link
Copy Markdown

Problem

applyOffsetCorrection looks for the tracked first visible item (the anchor) among the engaged indices first, and falls back to a full data search only when data length changed or a previous correction is still settling (ignoreScrollEvents).

There is a third case: items above the anchor were estimates (or the running estimate changes) and turn out much smaller when measured. The anchor's layout then moves up by the total difference, the next layout pass recomputes the engaged window at the unchanged scroll offset, and the anchor is no longer in it — although the user has not scrolled and the anchor is still the item on screen. The engaged search misses, the fallback is skipped, and no correction is applied at all: the content jumps by the full difference (easily hundreds of pixels after a few smaller-than-estimated items).

Fix

Also take the full-data fallback when the anchor, as recorded, still overlaps the viewport. An anchor the user scrolled away from does not qualify, so the existing behaviour for genuine scrolls is unchanged.

Tests

New src/__tests__/useRecyclerViewController.test.tsx (hook rendered with a real RecyclerViewManager; layout passes driven like RecyclerView's layout effect: measure → re-render passes → correction):

  • holds an anchor that measurements above it pushed out of the rendered window — 60 items × 500, scrolled to 15000, items 0–19 then measured at 50: after the passes the anchor (index 30) is outside the engaged window and the applied correction equals the anchor's movement. Fails on main (Expected: -9000, Received: 0), passes with the fix.
  • does not hold an anchor the user scrolled away from — same measurements after scrolling far away: no correction (guard; passes before and after).

Verified locally on the published src of 2.3.3 (identical to main) with Jest.

Notes

  • The fallback is O(n) over data, the same search already used for the other two cases; it only runs when the engaged search missed and the anchor is still on screen.

@neddtu

neddtu commented Oct 13, 2026

Copy link
Copy Markdown
Author

I have signed the CLA.

This branch has not been deployed

No deployments
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.

1 participant