Skip to content

Commit dbc2e96

Browse files
committed
Re-implement Server Action reducer
WIP
1 parent 3b64ac6 commit dbc2e96

File tree

6 files changed

+281
-194
lines changed

6 files changed

+281
-194
lines changed

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

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ export function startPPRNavigation(
8888
oldRouterState: FlightRouterState,
8989
newRouterState: FlightRouterState,
9090
shouldRefreshDynamicData: boolean,
91+
seedData: CacheNodeSeedData | null,
92+
seedHead: HeadData | null,
9193
prefetchData: CacheNodeSeedData | null,
9294
prefetchHead: HeadData | null,
9395
isPrefetchHeadPartial: boolean,
@@ -106,6 +108,8 @@ export function startPPRNavigation(
106108
newRouterState,
107109
shouldRefreshDynamicData,
108110
didFindRootLayout,
111+
seedData,
112+
seedHead,
109113
prefetchData,
110114
prefetchHead,
111115
isPrefetchHeadPartial,
@@ -125,6 +129,8 @@ function updateCacheNodeOnNavigation(
125129
newRouterState: FlightRouterState,
126130
shouldRefreshDynamicData: boolean,
127131
didFindRootLayout: boolean,
132+
seedData: CacheNodeSeedData | null,
133+
seedHead: HeadData | null,
128134
prefetchData: CacheNodeSeedData | null,
129135
prefetchHead: HeadData | null,
130136
isPrefetchHeadPartial: boolean,
@@ -146,6 +152,8 @@ function updateCacheNodeOnNavigation(
146152

147153
// Since we're switching to a different route tree, these are no
148154
// longer valid, because they correspond to the outer tree.
155+
seedData = null
156+
seedHead = null
149157
prefetchData = null
150158
prefetchHead = null
151159
isPrefetchHeadPartial = false
@@ -183,6 +191,8 @@ function updateCacheNodeOnNavigation(
183191
newRouterState,
184192
oldCacheNode,
185193
shouldRefreshDynamicData,
194+
seedData,
195+
seedHead,
186196
prefetchData,
187197
prefetchHead,
188198
isPrefetchHeadPartial,
@@ -194,6 +204,7 @@ function updateCacheNodeOnNavigation(
194204

195205
const newRouterStateChildren = newRouterState[1]
196206
const oldRouterStateChildren = oldRouterState[1]
207+
const seedDataChildren = seedData !== null ? seedData[1] : null
197208
const prefetchDataChildren = prefetchData !== null ? prefetchData[1] : null
198209

199210
// We're currently traversing the part of the tree that was also part of
@@ -242,6 +253,28 @@ function updateCacheNodeOnNavigation(
242253
// Reuse the existing CacheNode
243254
newCacheNode = reuseDynamicCacheNode(oldCacheNode, newParallelRoutes)
244255
needsDynamicRequest = false
256+
} else if (seedData !== null) {
257+
// If this navigation was the result of an action, then check if the
258+
// server sent back data in the action response. We should favor using
259+
// that, rather than performing a separate request. This is both better
260+
// for performance and it's more likely to be consistent with any
261+
// writes that were just performed by the action, compared to a
262+
// separate request.
263+
const seedRsc = seedData[0]
264+
const seedLoading = seedData[2]
265+
const isSeedRscPartial = false
266+
const isSeedHeadPartial = seedHead !== null
267+
newCacheNode = readCacheNodeFromSeedData(
268+
seedRsc,
269+
seedLoading,
270+
isSeedRscPartial,
271+
seedHead,
272+
isSeedHeadPartial,
273+
isLeafSegment,
274+
newParallelRoutes,
275+
navigatedAt
276+
)
277+
needsDynamicRequest = isLeafSegment && isSeedHeadPartial
245278
} else if (prefetchData !== null) {
246279
// Consult the prefetch cache.
247280
const prefetchRsc = prefetchData[0]
@@ -335,6 +368,8 @@ function updateCacheNodeOnNavigation(
335368
oldParallelRoutes !== undefined
336369
? oldParallelRoutes.get(parallelRouteKey)
337370
: undefined
371+
const seedDataChild: CacheNodeSeedData | void | null =
372+
seedDataChildren !== null ? seedDataChildren[parallelRouteKey] : null
338373
const prefetchDataChild: CacheNodeSeedData | void | null =
339374
prefetchDataChildren !== null
340375
? prefetchDataChildren[parallelRouteKey]
@@ -360,6 +395,8 @@ function updateCacheNodeOnNavigation(
360395
newRouterStateChild,
361396
shouldRefreshDynamicData,
362397
childDidFindRootLayout,
398+
seedDataChild ?? null,
399+
seedHead,
363400
prefetchDataChild ?? null,
364401
prefetchHead,
365402
isPrefetchHeadPartial,
@@ -384,7 +421,9 @@ function updateCacheNodeOnNavigation(
384421
taskChildren.set(parallelRouteKey, taskChild)
385422
const newCacheNodeChild = taskChild.node
386423
if (newCacheNodeChild !== null) {
387-
const newSegmentMapChild: ChildSegmentMap = new Map(oldSegmentMapChild)
424+
const newSegmentMapChild: ChildSegmentMap = new Map(
425+
shouldRefreshDynamicData ? undefined : oldSegmentMapChild
426+
)
388427
newSegmentMapChild.set(newSegmentKeyChild, newCacheNodeChild)
389428
newParallelRoutes.set(parallelRouteKey, newSegmentMapChild)
390429
}
@@ -434,6 +473,8 @@ function createCacheNodeOnNavigation(
434473
newRouterState: FlightRouterState,
435474
oldCacheNode: CacheNode | void,
436475
shouldRefreshDynamicData: boolean,
476+
seedData: CacheNodeSeedData | null,
477+
seedHead: HeadData | null,
437478
prefetchData: CacheNodeSeedData | null,
438479
prefetchHead: HeadData | null,
439480
isPrefetchHeadPartial: boolean,
@@ -452,6 +493,7 @@ function createCacheNodeOnNavigation(
452493
// diverges, which is why we keep them separate.
453494
const newRouterStateChildren = newRouterState[1]
454495
const prefetchDataChildren = prefetchData !== null ? prefetchData[1] : null
496+
const seedDataChildren = seedData !== null ? seedData[1] : null
455497
const oldParallelRoutes =
456498
oldCacheNode !== undefined ? oldCacheNode.parallelRoutes : undefined
457499
const newParallelRoutes = new Map(
@@ -489,6 +531,28 @@ function createCacheNodeOnNavigation(
489531
// Reuse the existing CacheNode
490532
newCacheNode = reuseDynamicCacheNode(oldCacheNode, newParallelRoutes)
491533
needsDynamicRequest = false
534+
} else if (seedData !== null) {
535+
// If this navigation was the result of an action, then check if the
536+
// server sent back data in the action response. We should favor using
537+
// that, rather than performing a separate request. This is both better
538+
// for performance and it's more likely to be consistent with any
539+
// writes that were just performed by the action, compared to a
540+
// separate request.
541+
const seedRsc = seedData[0]
542+
const seedLoading = seedData[2]
543+
const isSeedRscPartial = false
544+
const isSeedHeadPartial = seedHead !== null
545+
newCacheNode = readCacheNodeFromSeedData(
546+
seedRsc,
547+
seedLoading,
548+
isSeedRscPartial,
549+
seedHead,
550+
isSeedHeadPartial,
551+
isLeafSegment,
552+
newParallelRoutes,
553+
navigatedAt
554+
)
555+
needsDynamicRequest = isLeafSegment && isSeedHeadPartial
492556
} else if (prefetchData !== null) {
493557
// Consult the prefetch cache.
494558
const prefetchRsc = prefetchData[0]
@@ -533,6 +597,8 @@ function createCacheNodeOnNavigation(
533597
oldParallelRoutes !== undefined
534598
? oldParallelRoutes.get(parallelRouteKey)
535599
: undefined
600+
const seedDataChild: CacheNodeSeedData | void | null =
601+
seedDataChildren !== null ? seedDataChildren[parallelRouteKey] : null
536602
const prefetchDataChild: CacheNodeSeedData | void | null =
537603
prefetchDataChildren !== null
538604
? prefetchDataChildren[parallelRouteKey]
@@ -555,6 +621,8 @@ function createCacheNodeOnNavigation(
555621
newRouterStateChild,
556622
oldCacheNodeChild,
557623
shouldRefreshDynamicData,
624+
seedDataChild ?? null,
625+
seedHead,
558626
prefetchDataChild ?? null,
559627
prefetchHead,
560628
isPrefetchHeadPartial,
@@ -569,7 +637,9 @@ function createCacheNodeOnNavigation(
569637
taskChildren.set(parallelRouteKey, taskChild)
570638
const newCacheNodeChild = taskChild.node
571639
if (newCacheNodeChild !== null) {
572-
const newSegmentMapChild: ChildSegmentMap = new Map(oldSegmentMapChild)
640+
const newSegmentMapChild: ChildSegmentMap = new Map(
641+
shouldRefreshDynamicData ? undefined : oldSegmentMapChild
642+
)
573643
newSegmentMapChild.set(newSegmentKeyChild, newCacheNodeChild)
574644
newParallelRoutes.set(parallelRouteKey, newSegmentMapChild)
575645
}

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type {
55
RefreshAction,
66
} from '../router-reducer-types'
77
import { handleNavigationResult } from './navigate-reducer'
8-
import { refresh as refreshUsingSegmentCache } from '../../segment-cache/navigation'
8+
import { navigateToSeededRoute } from '../../segment-cache/navigation'
99
import { revalidateEntireCache } from '../../segment-cache/cache'
1010

1111
export function refreshReducer(
@@ -19,14 +19,31 @@ export function refreshReducer(
1919
const currentRouterState = state.tree
2020
revalidateEntireCache(currentNextUrl, currentRouterState)
2121

22+
// A refresh is modeled as a navigation to the current URL, but where any
23+
// existing dynamic data (including in shared layouts) is re-fetched.
2224
const currentUrl = new URL(state.canonicalUrl, action.origin)
23-
const result = refreshUsingSegmentCache(
25+
const url = currentUrl
26+
const currentFlightRouterState = state.tree
27+
const shouldScroll = true
28+
const shouldRefreshDynamicData = true
29+
30+
const seedFlightRouterState = state.tree
31+
const seedData = null
32+
const seedHead = null
33+
34+
const result = navigateToSeededRoute(
35+
url,
2436
currentUrl,
2537
state.cache,
26-
state.tree,
38+
currentFlightRouterState,
39+
seedFlightRouterState,
40+
seedData,
41+
seedHead,
42+
shouldRefreshDynamicData,
2743
state.nextUrl,
2844
state.renderedSearch,
29-
state.canonicalUrl
45+
state.canonicalUrl,
46+
shouldScroll
3047
)
3148

3249
const mutable: Mutable = {}

0 commit comments

Comments
 (0)