mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
2df0562f32
Specialize Cache Components prerender abort errors for `useParams`, `usePathname`, `useSearchParams`, `useSelectedLayoutSegment`, and `useSelectedLayoutSegments` instead of reporting a generic abort reason. React now allows errors observed after abort begins but before the final abort task runs to replace the generic abort reason. Client hook promises can use this window to report which hook blocked prerendering while preserving higher-priority synchronous I/O errors.
91 lines
3.4 KiB
Plaintext
91 lines
3.4 KiB
Plaintext
---
|
|
title: Client navigation hook requires a Suspense boundary
|
|
---
|
|
|
|
## Why This Error Occurred
|
|
|
|
When [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) is enabled, Next.js prerenders as much of a route as possible before a request arrives. A Client Component used a navigation hook whose value was not available during that prerender, but the component was not inside a [`Suspense`](https://react.dev/reference/react/Suspense) boundary.
|
|
|
|
This can happen with the following hooks:
|
|
|
|
- [`useSearchParams`](/docs/app/api-reference/functions/use-search-params), because the query string comes from the request URL
|
|
- [`useParams`](/docs/app/api-reference/functions/use-params), [`usePathname`](/docs/app/api-reference/functions/use-pathname), [`useSelectedLayoutSegment`](/docs/app/api-reference/functions/use-selected-layout-segment), or [`useSelectedLayoutSegments`](/docs/app/api-reference/functions/use-selected-layout-segments) when the route contains dynamic params that were not provided by [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params)
|
|
|
|
These hooks are reactive during client navigation. If their initial value is not known while prerendering, Next.js needs a fallback to include in the static shell until the runtime value is available.
|
|
|
|
## Possible Ways to Fix It
|
|
|
|
### Wrap the Client Component in Suspense
|
|
|
|
Wrap the smallest subtree that uses the hook in a `Suspense` boundary. Next.js can then prerender the fallback and replace it with the Client Component when the runtime value is available.
|
|
|
|
Before:
|
|
|
|
```jsx filename="app/dashboard/page.js"
|
|
import { Search } from './search'
|
|
|
|
export default function Page() {
|
|
return (
|
|
<main>
|
|
<h1>Dashboard</h1>
|
|
<Search />
|
|
</main>
|
|
)
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/dashboard/search.js"
|
|
'use client'
|
|
|
|
import { useSearchParams } from 'next/navigation'
|
|
|
|
export function Search() {
|
|
const searchParams = useSearchParams()
|
|
return <p>Search: {searchParams.get('q')}</p>
|
|
}
|
|
```
|
|
|
|
After:
|
|
|
|
```jsx filename="app/dashboard/page.js"
|
|
import { Suspense } from 'react'
|
|
import { Search } from './search'
|
|
|
|
export default function Page() {
|
|
return (
|
|
<main>
|
|
<h1>Dashboard</h1>
|
|
<Suspense fallback={<p>Loading search...</p>}>
|
|
<Search />
|
|
</Suspense>
|
|
</main>
|
|
)
|
|
}
|
|
```
|
|
|
|
The fallback should be synchronous and deterministic. Place the boundary close to the component that uses the hook so the rest of the route can remain in the prerendered shell.
|
|
|
|
### Prerender Known Dynamic Params
|
|
|
|
For hooks that derive their value from dynamic route params, use `generateStaticParams` when the possible values are known ahead of time:
|
|
|
|
```jsx filename="app/blog/[slug]/page.js"
|
|
export function generateStaticParams() {
|
|
return [{ slug: 'hello-world' }, { slug: 'release-notes' }]
|
|
}
|
|
|
|
export default function Page() {
|
|
return <BlogNavigation />
|
|
}
|
|
```
|
|
|
|
For the generated paths, `useParams`, `usePathname`, and the selected-layout-segment hooks can resolve during prerendering. Paths not returned by `generateStaticParams` may still require a `Suspense` boundary.
|
|
|
|
`generateStaticParams` does not provide search parameters. Components that use `useSearchParams` should be wrapped in `Suspense` when the route is prerendered.
|
|
|
|
## Useful Links
|
|
|
|
- [`Suspense`](https://react.dev/reference/react/Suspense)
|
|
- [`generateStaticParams`](/docs/app/api-reference/functions/generate-static-params)
|
|
- [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents)
|