fix(router): preserve scroll:false across async PPR retry navigations (force-dynamic)#94943
Open
sleitor wants to merge 1 commit into
Open
fix(router): preserve scroll:false across async PPR retry navigations (force-dynamic)#94943sleitor wants to merge 1 commit into
sleitor wants to merge 1 commit into
Conversation
When a force-dynamic page triggers a tree mismatch during a PPR navigation, the retry (ACTION_SERVER_PATCH) was hardcoding ScrollBehavior.Default, discarding the original scroll:false option. Thread scrollBehavior through the async retry chain: - spawnDynamicRequests() → finishNavigationTask() - finishNavigationTask() → dispatchRetryDueToTreeMismatch() - dispatchRetryDueToTreeMismatch() → ServerPatchAction.scrollBehavior - serverPatchReducer() reads action.scrollBehavior ?? Default Also update restore-reducer.ts which also calls spawnDynamicRequests() (history traversal, passes ScrollBehavior.Default). Fixes vercel#94893
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.
What?
Thread
scrollBehaviorthrough the async PPR retry chain so thatscroll: falsepassed torouter.replace()(orrouter.push()) is preserved when a force-dynamic page triggers a tree mismatch and the navigation falls back toACTION_SERVER_PATCH.Why?
On force-dynamic pages with PPR enabled, every navigation that hits an optimistic route cache entry ends up in a tree mismatch →
dispatchRetryDueToTreeMismatch→serverPatchReducer. Before this fix,serverPatchReducerhardcodedScrollBehavior.Defaultregardless of the original navigation'sscroll: falseoption, causing the page to scroll back to the top on every navigation.The bug only triggers in production (prefetching is disabled in dev) and only after the user has prefetched the root route (e.g. by hovering over a
<Link href="/">), which is why it's subtle.How?
scrollBehavior?: ScrollBehaviortoServerPatchActioninrouter-reducer-types.ts.scrollBehaviorparameter tospawnDynamicRequests()(afternavigationLock).spawnDynamicRequests→finishNavigationTask→dispatchRetryDueToTreeMismatch→ServerPatchAction.scrollBehavior.serverPatchReducer, readaction.scrollBehavior ?? ScrollBehavior.Defaultinstead of always usingDefault.restore-reducer.ts(the only other caller ofspawnDynamicRequests) to passScrollBehavior.Default— history traversal already defaults to no-scroll behavior.Fixes #94893