fix: Don't reset shallow URL updates on prefetch #58417
Closed
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.
Original PR #58297 from franky47
Description
Between 14.0.2-canary.6 and 14.0.2-canary.7, a change was introduced in #56497 that turned the Redux store state into a Promise, rather than a synchronous state update.
This caused the sync function -- used to send state updates to the Redux Devtools -- to be recreated on every dispatch, which in turn, by referential instability, caused the HistoryUpdater component to re-render and trigger a history.replaceState with no particular change, but with the internal canonicalUrl.
When an app does a soft/shallow navigation by calling history methods directly (currently the only way to do shallow search params updates in the app router), these changes would have been overwritten by any prefetch (eg: hovering or mounting a Link), which is usually a no-op for the navigation state.
This PR removes the sync function for the Redux devtools, as it cannot function as-is: actual state updates need to be awaited and forwarded somewhere else in the router if this behaviour is to be maintained, and should be decoupled from history calls to prevent side-effects.
Context
I maintain next-usequerystate, which is used in the Vercel dashboard, and which is impacted by this change (see
47ng/nuqs#388).
History
@timneutkens introduced the sync function and the whole Redux devtools reducer in #39866, with the note:
a new hook useReducerWithReduxDevtools has been added, we'll probably want to put this behind a compile-time flag when the new router is marked stable but until then it's useful to have it enabled by default (only
when you have Redux Devtools installed ofcourse).
If a different direction is needed to keep sending RENDER_SYNC actions to Redux devtools, I'll be happy to rework this PR to move the sync function into the action queue.
Changes
Added e2e test. Requires a start mode as prefetch links are disabled in development. Test was verified to fail from next@>=12.0.2-canary.7 without the fix.