Fix Virtualize user scroll during pending ScrollToItemAsync - #69288
Open
ilonatommy wants to merge 1 commit into
Open
ilonatommy wants to merge 1 commit into
ilonatommy wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Four unresolved moderate findings remain in the user-interruption and observer lifecycle paths.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Fixes a race where user scrolling could be overridden by an in-progress ScrollToItemAsync.
Changes:
- Adds one-shot spacer observation for interrupted programmatic scrolling.
- Cleans up observers and pending alignment state.
- Removes quarantine from the regression E2E test.
File summaries
| File | Summary and final review comments |
|---|---|
src/Components/Web.JS/src/Virtualize.ts |
Implements user-scroll interruption handling. Four unresolved moderate findings concern cancellation when spacers are outside the viewport (2 votes), stale pendingScrollCorrection (1 vote), uncleared pendingCallbacks (1 vote), and duplicate observers for Home/End paths (1 vote). |
src/Components/test/E2ETest/Tests/VirtualizationTest.cs |
Re-enables and documents the regression E2E test. |
Review details
Suppressed comments (3)
src/Components/Web.JS/src/Virtualize.ts:561
- When interrupting
RestoreSnapshot,restoreAnchorForShiftmay already have setpendingScrollCorrection. Leaving that flag set lets the nextrefreshObservedElementsapply the old correction to the user's new position, so the abandoned self-scroll can still move the viewport. ClearpendingScrollCorrectionhere along with the other pending alignment state.
pendingAlignLocalIndex = null;
src/Components/Web.JS/src/Virtualize.ts:558
- Queued entries from the main observer are left in
pendingCallbackswhen switching to the one-shot observer. If user input arrives during the 50 ms throttle window, the old programmatic entry is flushed later and treated as a current viewport-fill event, potentially starting another provider refresh for the abandoned target. Clear both spacer entries here, asbeginProgrammaticScrollalready does.
stopConvergenceObserving();
src/Components/Web.JS/src/Virtualize.ts:562
- When
EndorHomeinterrupts an active programmatic scroll, this call creates a one-shot observer, but those handlers immediately callreobserveSpacers()and start their own jump/convergence. Both observers can then deliver the same initial spacer state asUserScroll, causing duplicate spacer callbacks and provider-refresh churn. Avoid scheduling the one-shot for these explicit reobserve paths, or cancel it before reobserving.
observeSpacersAfterUserScroll();
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+270
to
+271
| scrollActivity.source = ScrollSource.UserScroll; | ||
| processIntersectionEntries(entries); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes a race where manual user scrolling does not reliably cancel an in-progress
Virtualize<TItem>.ScrollToItemAsyncoperation.When the target item is still loading, the rendered viewport can consist primarily of a large spacer. Scrolling within that spacer does not necessarily change its intersection state, so the existing
IntersectionObservermay not produce another callback. Without that callback, the pending provider request is not canceled and the original programmatic scroll can later override the user's position.Description
IntersectionObserverusing the same configuration as the main observer.ScrollToItem_UserScrollDuringProviderFetch_UserScrollWins.Fixes #68777