Repository navigation
DataViews: Fix infinite-scroll list jumping while a page loads - #79334
StevenDufresne wants to merge 2 commits into
Conversation
The infinite-scroll scroll-anchor restoration could move the scroll position out from under the user. On a window advance it captures an anchor element and its offset, then on a later render re-applies that offset. When pages load asynchronously the user keeps scrolling between capture and restore, and the restoration treated that user-driven movement as drift to "correct" — snapping the list back to the capture-time position and undoing the scroll. Store the scrollTop at capture and add the intervening scroll delta back into the adjustment, so only the content-driven shift (items added or removed above the anchor) is compensated. When the user does not scroll during the load the delta is zero and behaviour is unchanged. Also add an "Async Infinite Scroll" story that reveals data one page at a time asynchronously with a toggling isLoading, which reproduces the jump; the existing synchronous InfiniteScroll story never exercises the restoration path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Superseded by #79335 (re-opened from a branch on the main repo instead of a fork). Same commits. |
What?
Fixes a bug in DataViews infinite scroll where the list jumps (the scroll position is yanked upward) while you scroll down to load more, when the consumer loads pages asynchronously.
This PR also adds an
Async Infinite Scrollstory that reproduces the bug in one step.Why?
The infinite-scroll scroll-anchor restoration is meant to keep the viewport stable when items are inserted/removed (e.g. paging in older items). It works by capturing an anchor element and its viewport offset when the window advances, then re-applying that offset after the next render.
The problem: capture happens inside the throttled
scrollhandler the instant the window advances, but the restoration runs on a later render (it's gated onisLoading). When pages load asynchronously, the user keeps scrolling between capture and restore. The restoration can't distinguish that user-driven movement from a content-driven shift, so it "corrects" it — snapping the list back to where the anchor sat at capture time and undoing the scrolling the user did while the page was loading.The existing synchronous
InfiniteScrollstory never hits this: it passes noisLoadingand resolves data synchronously, so the restoration effect never runs and there's no async gap for the user to scroll into. Real consumers that load over the network (a notifications list, for example) hit it consistently.How?
Using content-position
Pand scrollS, an element's offset from the container top isP − S.viewportOffset = P1 − S1currentOffset = P2 − S2; the old adjustmentcurrentOffset − viewportOffsetresolves the scroll position toP2 − P1 + S1— i.e. it pins the anchor to its capture-time position, discarding the user's scroll(S2 − S1). For a pure scroll-down appendP2 = P1, so the adjustment isS1 − S2, exactly negating the user's scroll.The fix stores
scrollTopat capture and adds the intervening scroll delta back:So only the content-driven shift is compensated:
P2 = P1→ adjustment0→ no jump.P2 = P1 + H→ adjustmentH→ position correctly held.When the user does not scroll during the load,
scrollTop == capturedScrollTop, the added term is0, and behaviour is byte-for-byte identical to before — so this only changes the currently-broken case.Testing Instructions
npm run storybook:devpackages/dataviews/src/hooks/use-infinite-scroll.tsfromtrunk(git checkout trunk -- packages/dataviews/src/hooks/use-infinite-scroll.ts), keep the story, and repeat step 3 — the list jumps upward as each page settles.Testing Instructions for Keyboard
Not a UI/markup change. The list can still be scrolled with the keyboard (focus a row, then
Page Down/ arrow keys); the same stability applies.Screenshots or screencast
Use of AI Tools
This change was authored with the assistance of AI tooling (Claude Code). The root cause was diagnosed against a live consumer, the fix and the repro story were reviewed and verified by a human in Storybook before submitting.