Skip to content

Commit c67c431

Browse files
committed
Add refresh URL to reused default segments
When segment is reused in the "default" parallel route slot, it is not part of the new page. So if the page is refreshed, we must fetch its data from the previous URL, not the new URL. To track this we add the previous URL to a special field in the FlightRouterState. Currently this field is added by addRefreshMarkerToActiveParallelSegments; this updates the "ppr-navigations" module to add it during the main traversal used by navigations, so we can eventually get rid addRefreshMarkerToActiveParallelSegments. Note that we don't need to add the marker to _all_ page segments, just the ones that are not part of the new page.
1 parent 2386cb9 commit c67c431

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

packages/next/src/client/components/router-reducer/ppr-navigations.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export type Task = SPANavigationTask | MPANavigationTask
9191
// can be reused without initiating a server request.
9292
export function startPPRNavigation(
9393
navigatedAt: number,
94+
oldUrl: URL,
9495
oldCacheNode: CacheNode,
9596
oldRouterState: FlightRouterState,
9697
newRouterState: FlightRouterState,
@@ -103,6 +104,7 @@ export function startPPRNavigation(
103104
const segmentPath: Array<FlightSegmentPath> = []
104105
return updateCacheNodeOnNavigation(
105106
navigatedAt,
107+
oldUrl,
106108
oldCacheNode,
107109
oldRouterState,
108110
newRouterState,
@@ -118,6 +120,7 @@ export function startPPRNavigation(
118120

119121
function updateCacheNodeOnNavigation(
120122
navigatedAt: number,
123+
oldUrl: URL,
121124
oldCacheNode: CacheNode,
122125
oldRouterState: FlightRouterState,
123126
newRouterState: FlightRouterState,
@@ -230,7 +233,7 @@ function updateCacheNodeOnNavigation(
230233
// Reuse the existing Router State for this segment. We spawn a "task"
231234
// just to keep track of the updated router state; unlike most, it's
232235
// already fulfilled and won't be affected by the dynamic response.
233-
taskChild = spawnReusedTask(oldRouterStateChild)
236+
taskChild = reuseActiveSegmentInDefaultSlot(oldUrl, oldRouterStateChild)
234237
} else {
235238
// There's no currently active segment. Switch to the "create" path.
236239
taskChild = beginRenderingNewRouteTree(
@@ -299,6 +302,7 @@ function updateCacheNodeOnNavigation(
299302
// the children.
300303
taskChild = updateCacheNodeOnNavigation(
301304
navigatedAt,
305+
oldUrl,
302306
oldCacheNodeChild,
303307
oldRouterStateChild,
304308
newRouterStateChild,
@@ -726,9 +730,37 @@ function spawnPendingTask(
726730
return newTask
727731
}
728732

729-
function spawnReusedTask(reusedRouterState: FlightRouterState): Task {
730-
// Create a task that reuses an existing segment, e.g. when reusing
731-
// the current active segment in place of a default route.
733+
function reuseActiveSegmentInDefaultSlot(
734+
oldUrl: URL,
735+
oldRouterState: FlightRouterState
736+
): Task {
737+
// This is a "default" segment. These are never sent by the server during a
738+
// soft navigation; instead, the client reuses whatever segment was already
739+
// active in that slot on the previous route. This means if we later need to
740+
// refresh the segment, it will have to be refetched from the previous route's
741+
// URL. We store it in the Flight Router State.
742+
//
743+
// TODO: We also mark the segment with a "refresh" marker but I think we can
744+
// get rid of that eventually by making sure we only add URLs to page segments
745+
// that are reused. Then the presence of the URL alone is enough.
746+
let reusedRouterState
747+
748+
const oldRefreshMarker = oldRouterState[3]
749+
if (oldRefreshMarker === 'refresh') {
750+
// This segment was already reused from an even older route. Keep its
751+
// existing URL and refresh marker.
752+
reusedRouterState = oldRouterState
753+
} else {
754+
// This segment was not previously reused, and it's not on the new route.
755+
// So it must have been delivered in the old route.
756+
reusedRouterState = patchRouterStateWithNewChildren(
757+
oldRouterState,
758+
oldRouterState[1]
759+
)
760+
reusedRouterState[2] = oldUrl.href
761+
reusedRouterState[3] = 'refresh'
762+
}
763+
732764
return {
733765
route: reusedRouterState,
734766
node: null,

packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,13 +267,14 @@ export function navigateReducer(
267267
return handleExternalUrl(state, mutable, flightData, pendingPush)
268268
}
269269

270+
const oldCanonicalUrl = state.canonicalUrl
270271
const updatedCanonicalUrl = canonicalUrlOverride
271272
? createHrefFromUrl(canonicalUrlOverride)
272273
: href
273274

274275
const onlyHashChange =
275276
!!hash &&
276-
state.canonicalUrl.split('#', 1)[0] ===
277+
oldCanonicalUrl.split('#', 1)[0] ===
277278
updatedCanonicalUrl.split('#', 1)[0]
278279

279280
// If only the hash has changed, the server hasn't sent us any new data. We can just update
@@ -339,6 +340,7 @@ export function navigateReducer(
339340
) {
340341
const task = startPPRNavigation(
341342
navigatedAt,
343+
new URL(oldCanonicalUrl, url.origin),
342344
currentCache,
343345
currentTree,
344346
treePatch,

0 commit comments

Comments
 (0)