Skip to content

Commit 79e36e7

Browse files
committed
ensure router cache updates reference the latest cache values
1 parent 3c99b8c commit 79e36e7

File tree

22 files changed

+167
-4
lines changed

22 files changed

+167
-4
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ function navigateReducer_noPPR(
167167
updatedCanonicalUrl.split('#', 1)[0]
168168

169169
let currentTree = state.tree
170-
const currentCache = state.cache
170+
let currentCache = state.cache
171171
let scrollableSegments: FlightSegmentPath[] = []
172172
for (const flightDataPath of flightData) {
173173
const flightSegmentPath = flightDataPath.slice(
@@ -258,6 +258,9 @@ function navigateReducer_noPPR(
258258
mutable.cache = cache
259259
} else if (applied) {
260260
mutable.cache = cache
261+
// If we applied the cache, we update the "current cache" value so any other
262+
// segments in the FlightDataPath will be able to reference the updated cache.
263+
currentCache = cache
261264
}
262265

263266
currentTree = newTree

test/e2e/app-dir/app-client-cache/client-cache.defaults.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import {
77
fastForwardTo,
88
getPathname,
99
} from './test-utils'
10+
import path from 'path'
1011

1112
describe('app dir client cache semantics (default semantics)', () => {
1213
const { next, isNextDev } = nextTestSetup({
13-
files: __dirname,
14+
files: path.join(__dirname, 'fixture', 'regular'),
1415
})
1516

1617
if (isNextDev) {

test/e2e/app-dir/app-client-cache/client-cache.experimental.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { nextTestSetup } from 'e2e-utils'
22
import { browserConfigWithFixedTime, fastForwardTo } from './test-utils'
33
import { findAllTelemetryEvents } from 'next-test-utils'
4+
import path from 'path'
45

56
describe('app dir client cache semantics (experimental staleTimes)', () => {
67
describe('dynamic: 0', () => {
78
const { next, isNextDev } = nextTestSetup({
8-
files: __dirname,
9+
files: path.join(__dirname, 'fixture', 'regular'),
910
nextConfig: {
1011
experimental: { staleTimes: { dynamic: 0 } },
1112
},

test/e2e/app-dir/app-client-cache/client-cache.original.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import {
77
fastForwardTo,
88
getPathname,
99
} from './test-utils'
10+
import path from 'path'
1011

1112
// This preserves existing tests for the 30s/5min heuristic (previous router defaults)
1213
describe('app dir client cache semantics (30s/5min)', () => {
1314
const { next, isNextDev } = nextTestSetup({
14-
files: __dirname,
15+
files: path.join(__dirname, 'fixture', 'regular'),
1516
nextConfig: {
1617
experimental: { staleTimes: { dynamic: 30, static: 180 } },
1718
},
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { nextTestSetup } from 'e2e-utils'
2+
import { check } from 'next-test-utils'
3+
import { BrowserInterface } from 'next-webdriver'
4+
import {
5+
browserConfigWithFixedTime,
6+
createRequestsListener,
7+
fastForwardTo,
8+
getPathname,
9+
} from './test-utils'
10+
import path from 'path'
11+
12+
describe('app dir client cache with parallel routes', () => {
13+
const { next } = nextTestSetup({
14+
files: path.join(__dirname, 'fixtures', 'parallel-routes'),
15+
})
16+
17+
describe('prefetch={true}', () => {
18+
let browser: BrowserInterface
19+
20+
beforeEach(async () => {
21+
browser = (await next.browser(
22+
'/',
23+
browserConfigWithFixedTime
24+
)) as BrowserInterface
25+
})
26+
27+
it('should prefetch the full page', async () => {
28+
const { getRequests, clearRequests } =
29+
await createRequestsListener(browser)
30+
await check(() => {
31+
return getRequests().some(
32+
([url, didPartialPrefetch]) =>
33+
getPathname(url) === '/0' && !didPartialPrefetch
34+
)
35+
? 'success'
36+
: 'fail'
37+
}, 'success')
38+
39+
clearRequests()
40+
41+
await browser
42+
.elementByCss('[href="/0"]')
43+
.click()
44+
.waitForElementByCss('#random-number')
45+
46+
expect(getRequests().every(([url]) => getPathname(url) !== '/0')).toEqual(
47+
true
48+
)
49+
})
50+
51+
it('should re-use the cache for the full page, only for 5 mins', async () => {
52+
const randomNumber = await browser
53+
.elementByCss('[href="/0"]')
54+
.click()
55+
.waitForElementByCss('#random-number')
56+
.text()
57+
58+
await browser.elementByCss('[href="/"]').click()
59+
60+
const number = await browser
61+
.elementByCss('[href="/0"]')
62+
.click()
63+
.waitForElementByCss('#random-number')
64+
.text()
65+
66+
expect(number).toBe(randomNumber)
67+
68+
await browser.eval(fastForwardTo, 5 * 60 * 1000)
69+
70+
await browser.elementByCss('[href="/"]').click()
71+
72+
const newNumber = await browser
73+
.elementByCss('[href="/0"]')
74+
.click()
75+
.waitForElementByCss('#random-number')
76+
.text()
77+
78+
expect(newNumber).not.toBe(randomNumber)
79+
})
80+
})
81+
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Page({ params }) {
2+
return (
3+
<div>
4+
Catchall <pre>{JSON.stringify(params)}</pre>{' '}
5+
</div>
6+
)
7+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Page() {
2+
return <div>Root Breadcrumb</div>
3+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Link from 'next/link'
2+
3+
export default async function Page() {
4+
const randomNumber = await new Promise((resolve) => {
5+
setTimeout(() => {
6+
resolve(Math.random())
7+
}, 1000)
8+
})
9+
10+
return (
11+
<>
12+
<div>
13+
<Link href="/">Back to Home</Link>
14+
</div>
15+
<div id="random-number">{randomNumber}</div>
16+
</>
17+
)
18+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export default function Root({ children, breadcrumbs }) {
2+
return (
3+
<html>
4+
<head></head>
5+
<body>
6+
<div>{breadcrumbs}</div>
7+
<div id="root-layout">Root Layout</div>
8+
<div>{children}</div>
9+
</body>
10+
</html>
11+
)
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Link from 'next/link'
2+
3+
export default function Page() {
4+
return (
5+
<div>
6+
<Link href="/0" prefetch={true}>
7+
To Dynamic Page
8+
</Link>
9+
</div>
10+
)
11+
}

0 commit comments

Comments
 (0)