fix(next): initial prefetch cache not set properly with different search params (#65977)
cc @icyJoseph @ztanner NOTE: The canary release [`v14.1.1-canary.51`](https://github.com/vercel/next.js/releases/tag/v14.1.1-canary.51) and below work as expected. ### Why? Introduced from #61535, the initial prefetch cache is set based on the `location.pathname`. When a page is loaded WITH the search param, the cache key does not contain information of the search param. The issue is when on a dynamic page reading the `searchParams` value, the value doesn't change if navigated as: ``` /?q=foo --> / ``` The prefetch cache hits, not re-rendering, and the `searchParams` value is not passed properly. ### How? For the prefetch cache, add the `location.search` as well. Since `createPrefetchCacheKey` uses [`createHrefFromUrl`](https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/router-reducer/create-href-from-url.ts) which includes `location.search`, I'm expecting the change won't affect current cache key behavior. Fixes #64170 Fixes #65030 --------- Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
This commit is contained in:
parent
8a429e083e
commit
79c934aaec
5 changed files with 53 additions and 1 deletions
|
@ -101,7 +101,10 @@ export function createInitialRouterState({
|
|||
// Seed the prefetch cache with this page's data.
|
||||
// This is to prevent needlessly re-prefetching a page that is already reusable,
|
||||
// and will avoid triggering a loading state/data fetch stall when navigating back to the page.
|
||||
const url = new URL(location.pathname, location.origin)
|
||||
const url = new URL(
|
||||
`${location.pathname}${location.search}`,
|
||||
location.origin
|
||||
)
|
||||
|
||||
const initialFlightData: FlightData = [['', initialTree, null, null]]
|
||||
createPrefetchCacheEntryForInitialLoad({
|
||||
|
|
7
test/e2e/app-dir/prefetch-searchparam/app/layout.tsx
Normal file
7
test/e2e/app-dir/prefetch-searchparam/app/layout.tsx
Normal file
|
@ -0,0 +1,7 @@
|
|||
export default function Root({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
11
test/e2e/app-dir/prefetch-searchparam/app/page.tsx
Normal file
11
test/e2e/app-dir/prefetch-searchparam/app/page.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import Link from 'next/link'
|
||||
|
||||
export default function Page({ searchParams }: { searchParams: any }) {
|
||||
return (
|
||||
<>
|
||||
<Link href="/">/</Link>
|
||||
<Link href="/?q=bar">/?q=bar</Link>
|
||||
<p>{JSON.stringify(searchParams)}</p>
|
||||
</>
|
||||
)
|
||||
}
|
6
test/e2e/app-dir/prefetch-searchparam/next.config.js
Normal file
6
test/e2e/app-dir/prefetch-searchparam/next.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* @type {import('next').NextConfig}
|
||||
*/
|
||||
const nextConfig = {}
|
||||
|
||||
module.exports = nextConfig
|
|
@ -0,0 +1,25 @@
|
|||
import { nextTestSetup } from 'e2e-utils'
|
||||
import { retry } from 'next-test-utils'
|
||||
|
||||
describe('prefetch-searchparam', () => {
|
||||
const { next } = nextTestSetup({
|
||||
files: __dirname,
|
||||
})
|
||||
it('should set prefetch cache properly on different search params', async () => {
|
||||
// load WITH search param
|
||||
const browser = await next.browser('/?q=foo')
|
||||
expect(await browser.elementByCss('p').text()).toBe('{"q":"foo"}')
|
||||
|
||||
// navigate to different search param, should update the search param
|
||||
await browser.elementByCss('[href="/?q=bar"]').click()
|
||||
await retry(async () => {
|
||||
expect(await browser.elementByCss('p').text()).toBe('{"q":"bar"}')
|
||||
})
|
||||
|
||||
// navigate to home, should clear the searchParams value
|
||||
await browser.elementByCss('[href="/"]').click()
|
||||
await retry(async () => {
|
||||
expect(await browser.elementByCss('p').text()).toBe('{}')
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue