.
This commit is contained in:
Generated
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: getInitialProps
|
||||
description: Fetch dynamic data on the server for your React component with getInitialProps.
|
||||
---
|
||||
|
||||
> **Good to know**: `getInitialProps` is a legacy API. We recommend using [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) or [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props) instead.
|
||||
|
||||
`getInitialProps` is an `async` function that can be added to the default exported React component for the page. It will run on both the server-side and again on the client-side during page transitions. The result of the function will be forwarded to the React component as `props`.
|
||||
|
||||
```tsx filename="pages/index.tsx" switcher
|
||||
import { NextPageContext } from 'next'
|
||||
|
||||
Page.getInitialProps = async (ctx: NextPageContext) => {
|
||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
||||
const json = await res.json()
|
||||
return { stars: json.stargazers_count }
|
||||
}
|
||||
|
||||
export default function Page({ stars }: { stars: number }) {
|
||||
return stars
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/index.js" switcher
|
||||
Page.getInitialProps = async (ctx) => {
|
||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
||||
const json = await res.json()
|
||||
return { stars: json.stargazers_count }
|
||||
}
|
||||
|
||||
export default function Page({ stars }) {
|
||||
return stars
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**:
|
||||
>
|
||||
> - Data returned from `getInitialProps` is serialized when server rendering. Ensure the returned object from `getInitialProps` is a plain `Object`, and not using `Date`, `Map` or `Set`.
|
||||
> - For the initial page load, `getInitialProps` will run on the server only. `getInitialProps` will then also run on the client when navigating to a different route with the [`next/link`](/docs/pages/api-reference/components/link) component or by using [`next/router`](/docs/pages/api-reference/functions/use-router).
|
||||
> - If `getInitialProps` is used in a custom `_app.js`, and the page being navigated to is using `getServerSideProps`, then `getInitialProps` will **only** run on the server.
|
||||
|
||||
## Context Object
|
||||
|
||||
`getInitialProps` receives a single argument called `context`, which is an object with the following properties:
|
||||
|
||||
| Name | Description |
|
||||
| ---------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| `pathname` | Current route, the path of the page in `/pages` |
|
||||
| `query` | Query string of the URL, parsed as an object |
|
||||
| `asPath` | `String` of the actual path (including the query) shown in the browser |
|
||||
| `req` | [HTTP request object](https://nodejs.org/api/http.html#http_class_http_incomingmessage) (server only) |
|
||||
| `res` | [HTTP response object](https://nodejs.org/api/http.html#http_class_http_serverresponse) (server only) |
|
||||
| `err` | Error object if any error is encountered during the rendering |
|
||||
|
||||
## Caveats
|
||||
|
||||
- `getInitialProps` can only be used in `pages/` top level files, and not in nested components. To have nested data fetching at the component level, consider exploring the [App Router](/docs/app/getting-started/fetching-data).
|
||||
- Regardless of whether your route is static or dynamic, any data returned from `getInitialProps` as `props` will be able to be examined on the client-side in the initial HTML. This is to allow the page to be [hydrated](https://react.dev/reference/react-dom/hydrate) correctly. Make sure that you don't pass any sensitive information that shouldn't be available on the client in `props`.
|
||||
Generated
Vendored
+140
@@ -0,0 +1,140 @@
|
||||
---
|
||||
title: getServerSideProps
|
||||
description: API reference for `getServerSideProps`. Learn how to fetch data on each request with Next.js.
|
||||
---
|
||||
|
||||
When exporting a function called `getServerSideProps` (Server-Side Rendering) from a page, Next.js will prerender this page on each request using the data returned by `getServerSideProps`. This is useful if you want to fetch data that changes often, and have the page update to show the most current data.
|
||||
|
||||
```tsx filename="pages/index.tsx" switcher
|
||||
import type { InferGetServerSidePropsType, GetServerSideProps } from 'next'
|
||||
|
||||
type Repo = {
|
||||
name: string
|
||||
stargazers_count: number
|
||||
}
|
||||
|
||||
export const getServerSideProps = (async () => {
|
||||
// Fetch data from external API
|
||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
||||
const repo: Repo = await res.json()
|
||||
// Pass data to the page via props
|
||||
return { props: { repo } }
|
||||
}) satisfies GetServerSideProps<{ repo: Repo }>
|
||||
|
||||
export default function Page({
|
||||
repo,
|
||||
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
return (
|
||||
<main>
|
||||
<p>{repo.stargazers_count}</p>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/index.js" switcher
|
||||
export async function getServerSideProps() {
|
||||
// Fetch data from external API
|
||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
||||
const repo = await res.json()
|
||||
// Pass data to the page via props
|
||||
return { props: { repo } }
|
||||
}
|
||||
|
||||
export default function Page({ repo }) {
|
||||
return (
|
||||
<main>
|
||||
<p>{repo.stargazers_count}</p>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
You can import modules in top-level scope for use in `getServerSideProps`. Imports used will **not be bundled for the client-side**. This means you can write **server-side code directly in `getServerSideProps`**, including fetching data from your database.
|
||||
|
||||
## Context parameter
|
||||
|
||||
The `context` parameter is an object containing the following keys:
|
||||
|
||||
| Name | Description |
|
||||
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `params` | If this page uses a [dynamic route](/docs/pages/building-your-application/routing/dynamic-routes), `params` contains the route parameters. If the page name is `[id].js`, then `params` will look like `{ id: ... }`. |
|
||||
| `req` | [The `HTTP` IncomingMessage object](https://nodejs.org/api/http.html#http_class_http_incomingmessage), with an additional `cookies` prop, which is an object with string keys mapping to string values of cookies. |
|
||||
| `res` | [The `HTTP` response object](https://nodejs.org/api/http.html#http_class_http_serverresponse). |
|
||||
| `query` | An object representing the query string, including dynamic route parameters. |
|
||||
| `preview` | (Deprecated for `draftMode`) `preview` is `true` if the page is in the [Preview Mode](/docs/pages/guides/preview-mode) and `false` otherwise. |
|
||||
| `previewData` | (Deprecated for `draftMode`) The [preview](/docs/pages/guides/preview-mode) data set by `setPreviewData`. |
|
||||
| `draftMode` | `draftMode` is `true` if the page is in the [Draft Mode](/docs/pages/guides/draft-mode) and `false` otherwise. |
|
||||
| `resolvedUrl` | A normalized version of the request `URL` that strips the `_next/data` prefix for client transitions and includes original query values. |
|
||||
| `locale` | Contains the active locale (if enabled). |
|
||||
| `locales` | Contains all supported locales (if enabled). |
|
||||
| `defaultLocale` | Contains the configured default locale (if enabled). |
|
||||
|
||||
## getServerSideProps return values
|
||||
|
||||
The `getServerSideProps` function should return an object with **any one of the following** properties:
|
||||
|
||||
### `props`
|
||||
|
||||
The `props` object is a key-value pair, where each value is received by the page component. It should be a [serializable object](https://developer.mozilla.org/docs/Glossary/Serialization) so that any props passed, could be serialized with [`JSON.stringify`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).
|
||||
|
||||
```jsx
|
||||
export async function getServerSideProps(context) {
|
||||
return {
|
||||
props: { message: `Next.js is awesome` }, // will be passed to the page component as props
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `notFound`
|
||||
|
||||
The `notFound` boolean allows the page to return a `404` status and [404 Page](/docs/pages/building-your-application/routing/custom-error#404-page). With `notFound: true`, the page will return a `404` even if there was a successfully generated page before. This is meant to support use cases like user-generated content getting removed by its author.
|
||||
|
||||
```js
|
||||
export async function getServerSideProps(context) {
|
||||
const res = await fetch(`https://.../data`)
|
||||
const data = await res.json()
|
||||
|
||||
if (!data) {
|
||||
return {
|
||||
notFound: true,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: { data }, // will be passed to the page component as props
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `redirect`
|
||||
|
||||
The `redirect` object allows redirecting to internal and external resources. It should match the shape of `{ destination: string, permanent: boolean }`. In some rare cases, you might need to assign a custom status code for older `HTTP` clients to properly redirect. In these cases, you can use the `statusCode` property instead of the `permanent` property, but not both.
|
||||
|
||||
```js
|
||||
export async function getServerSideProps(context) {
|
||||
const res = await fetch(`https://.../data`)
|
||||
const data = await res.json()
|
||||
|
||||
if (!data) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/',
|
||||
permanent: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {}, // will be passed to the page component as props
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Changes |
|
||||
| --------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `v13.4.0` | [App Router](/docs/app/getting-started/fetching-data) is now stable with simplified data fetching |
|
||||
| `v10.0.0` | `locale`, `locales`, `defaultLocale`, and `notFound` options added. |
|
||||
| `v9.3.0` | `getServerSideProps` introduced. |
|
||||
Generated
Vendored
+259
@@ -0,0 +1,259 @@
|
||||
---
|
||||
title: getStaticPaths
|
||||
description: API reference for `getStaticPaths`. Learn how to fetch data and generate static pages with `getStaticPaths`.
|
||||
---
|
||||
|
||||
When exporting a function called `getStaticPaths` from a page that uses [Dynamic Routes](/docs/pages/building-your-application/routing/dynamic-routes), Next.js will statically prerender all the paths specified by `getStaticPaths`.
|
||||
|
||||
```tsx filename="pages/repo/[name].tsx" switcher
|
||||
import type {
|
||||
InferGetStaticPropsType,
|
||||
GetStaticProps,
|
||||
GetStaticPaths,
|
||||
} from 'next'
|
||||
|
||||
type Repo = {
|
||||
name: string
|
||||
stargazers_count: number
|
||||
}
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
return {
|
||||
paths: [
|
||||
{
|
||||
params: {
|
||||
name: 'next.js',
|
||||
},
|
||||
}, // See the "paths" section below
|
||||
],
|
||||
fallback: true, // false or "blocking"
|
||||
}
|
||||
}) satisfies GetStaticPaths
|
||||
|
||||
export const getStaticProps = (async (context) => {
|
||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
||||
const repo = await res.json()
|
||||
return { props: { repo } }
|
||||
}) satisfies GetStaticProps<{
|
||||
repo: Repo
|
||||
}>
|
||||
|
||||
export default function Page({
|
||||
repo,
|
||||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||
return repo.stargazers_count
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/repo/[name].js" switcher
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: [
|
||||
{
|
||||
params: {
|
||||
name: 'next.js',
|
||||
},
|
||||
}, // See the "paths" section below
|
||||
],
|
||||
fallback: true, // false or "blocking"
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
||||
const repo = await res.json()
|
||||
return { props: { repo } }
|
||||
}
|
||||
|
||||
export default function Page({ repo }) {
|
||||
return repo.stargazers_count
|
||||
}
|
||||
```
|
||||
|
||||
## getStaticPaths return values
|
||||
|
||||
The `getStaticPaths` function should return an object with the following **required** properties:
|
||||
|
||||
### `paths`
|
||||
|
||||
The `paths` key determines which paths will be prerendered. For example, suppose that you have a page that uses [Dynamic Routes](/docs/pages/building-your-application/routing/dynamic-routes) named `pages/posts/[id].js`. If you export `getStaticPaths` from this page and return the following for `paths`:
|
||||
|
||||
```js
|
||||
return {
|
||||
paths: [
|
||||
{ params: { id: '1' }},
|
||||
{
|
||||
params: { id: '2' },
|
||||
// with i18n configured the locale for the path can be returned as well
|
||||
locale: "en",
|
||||
},
|
||||
],
|
||||
fallback: ...
|
||||
}
|
||||
```
|
||||
|
||||
Then, Next.js will statically generate `/posts/1` and `/posts/2` during `next build` using the page component in `pages/posts/[id].js`.
|
||||
|
||||
The value for each `params` object must match the parameters used in the page name:
|
||||
|
||||
- If the page name is `pages/posts/[postId]/[commentId]`, then `params` should contain `postId` and `commentId`.
|
||||
- If the page name uses [catch-all routes](/docs/pages/building-your-application/routing/dynamic-routes#catch-all-segments) like `pages/[...slug]`, then `params` should contain `slug` (which is an array). If this array is `['hello', 'world']`, then Next.js will statically generate the page at `/hello/world`.
|
||||
- If the page uses an [optional catch-all route](/docs/pages/building-your-application/routing/dynamic-routes#optional-catch-all-segments), use `null`, `[]`, `undefined` or `false` to render the root-most route. For example, if you supply `slug: false` for `pages/[[...slug]]`, Next.js will statically generate the page `/`.
|
||||
|
||||
The `params` strings are **case-sensitive** and ideally should be normalized to ensure the paths are generated correctly. For example, if `WoRLD` is returned for a param it will only match if `WoRLD` is the actual path visited, not `world` or `World`.
|
||||
|
||||
Separate of the `params` object a `locale` field can be returned when [i18n is configured](/docs/pages/guides/internationalization), which configures the locale for the path being generated.
|
||||
|
||||
### `fallback: false`
|
||||
|
||||
If `fallback` is `false`, then any paths not returned by `getStaticPaths` will result in a **404 page**.
|
||||
|
||||
When `next build` is run, Next.js will check if `getStaticPaths` returned `fallback: false`, it will then build **only** the paths returned by `getStaticPaths`. This option is useful if you have a small number of paths to create, or new page data is not added often. If you find that you need to add more paths, and you have `fallback: false`, you will need to run `next build` again so that the new paths can be generated.
|
||||
|
||||
The following example prerenders one blog post per page called `pages/posts/[id].js`. The list of blog posts will be fetched from a CMS and returned by `getStaticPaths`. Then, for each page, it fetches the post data from a CMS using [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props).
|
||||
|
||||
```jsx filename="pages/posts/[id].js"
|
||||
function Post({ post }) {
|
||||
// Render post...
|
||||
}
|
||||
|
||||
// This function gets called at build time
|
||||
export async function getStaticPaths() {
|
||||
// Call an external API endpoint to get posts
|
||||
const res = await fetch('https://.../posts')
|
||||
const posts = await res.json()
|
||||
|
||||
// Get the paths we want to prerender based on posts
|
||||
const paths = posts.map((post) => ({
|
||||
params: { id: post.id },
|
||||
}))
|
||||
|
||||
// We'll prerender only these paths at build time.
|
||||
// { fallback: false } means other routes should 404.
|
||||
return { paths, fallback: false }
|
||||
}
|
||||
|
||||
// This also gets called at build time
|
||||
export async function getStaticProps({ params }) {
|
||||
// params contains the post `id`.
|
||||
// If the route is like /posts/1, then params.id is 1
|
||||
const res = await fetch(`https://.../posts/${params.id}`)
|
||||
const post = await res.json()
|
||||
|
||||
// Pass post data to the page via props
|
||||
return { props: { post } }
|
||||
}
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
### `fallback: true`
|
||||
|
||||
<details>
|
||||
<summary>Examples</summary>
|
||||
|
||||
- [Static generation of a large number of pages](https://react-tweet.vercel.app/)
|
||||
|
||||
</details>
|
||||
|
||||
If `fallback` is `true`, then the behavior of `getStaticProps` changes in the following ways:
|
||||
|
||||
- The paths returned from `getStaticPaths` will be rendered to `HTML` at build time by `getStaticProps`.
|
||||
- The paths that have not been generated at build time will **not** result in a 404 page. Instead, Next.js will serve a [“fallback”](#fallback-pages) version of the page on the first request to such a path. Web crawlers, such as Google, won't be served a fallback and instead the path will behave as in [`fallback: 'blocking'`](#fallback-blocking).
|
||||
- When a page with `fallback: true` is navigated to through `next/link` or `next/router` (client-side) Next.js will _not_ serve a fallback and instead the page will behave as [`fallback: 'blocking'`](#fallback-blocking).
|
||||
- In the background, Next.js will statically generate the requested path `HTML` and `JSON`. This includes running `getStaticProps`.
|
||||
- When complete, the browser receives the `JSON` for the generated path. This will be used to automatically render the page with the required props. From the user’s perspective, the page will be swapped from the fallback page to the full page.
|
||||
- At the same time, Next.js adds this path to the list of prerendered pages. Subsequent requests to the same path will serve the generated page, like other pages prerendered at build time.
|
||||
|
||||
> **Good to know**: `fallback: true` is not supported when using [`output: 'export'`](/docs/pages/guides/static-exports).
|
||||
|
||||
#### When is `fallback: true` useful?
|
||||
|
||||
`fallback: true` is useful if your app has a very large number of static pages that depend on data (such as a very large e-commerce site). If you want to prerender all product pages, the builds would take a very long time.
|
||||
|
||||
Instead, you may statically generate a small subset of pages and use `fallback: true` for the rest. When someone requests a page that is not generated yet, the user will see the page with a loading indicator or skeleton component.
|
||||
|
||||
Shortly after, `getStaticProps` finishes and the page will be rendered with the requested data. From now on, everyone who requests the same page will get the statically prerendered page.
|
||||
|
||||
This ensures that users always have a fast experience while preserving fast builds and the benefits of Static Generation.
|
||||
|
||||
`fallback: true` will not _update_ generated pages, for that take a look at [Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration).
|
||||
|
||||
### `fallback: 'blocking'`
|
||||
|
||||
If `fallback` is `'blocking'`, new paths not returned by `getStaticPaths` will wait for the `HTML` to be generated, identical to SSR (hence why _blocking_), and then be cached for future requests so it only happens once per path.
|
||||
|
||||
`getStaticProps` will behave as follows:
|
||||
|
||||
- The paths returned from `getStaticPaths` will be rendered to `HTML` at build time by `getStaticProps`.
|
||||
- The paths that have not been generated at build time will **not** result in a 404 page. Instead, Next.js will SSR on the first request and return the generated `HTML`.
|
||||
- When complete, the browser receives the `HTML` for the generated path. From the user’s perspective, it will transition from "the browser is requesting the page" to "the full page is loaded". There is no flash of loading/fallback state.
|
||||
- At the same time, Next.js adds this path to the list of prerendered pages. Subsequent requests to the same path will serve the generated page, like other pages prerendered at build time.
|
||||
|
||||
`fallback: 'blocking'` will not _update_ generated pages by default. To update generated pages, use [Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration) in conjunction with `fallback: 'blocking'`.
|
||||
|
||||
> **Good to know**: `fallback: 'blocking'` is not supported when using [`output: 'export'`](/docs/pages/guides/static-exports).
|
||||
|
||||
### Fallback pages
|
||||
|
||||
In the “fallback” version of a page:
|
||||
|
||||
- The page’s props will be empty.
|
||||
- Using the [router](/docs/pages/api-reference/functions/use-router), you can detect if the fallback is being rendered, `router.isFallback` will be `true`.
|
||||
|
||||
The following example showcases using `isFallback`:
|
||||
|
||||
```jsx filename="pages/posts/[id].js"
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
function Post({ post }) {
|
||||
const router = useRouter()
|
||||
|
||||
// If the page is not yet generated, this will be displayed
|
||||
// initially until getStaticProps() finishes running
|
||||
if (router.isFallback) {
|
||||
return <div>Loading...</div>
|
||||
}
|
||||
|
||||
// Render post...
|
||||
}
|
||||
|
||||
// This function gets called at build time
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
// Only `/posts/1` and `/posts/2` are generated at build time
|
||||
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
|
||||
// Enable statically generating additional pages
|
||||
// For example: `/posts/3`
|
||||
fallback: true,
|
||||
}
|
||||
}
|
||||
|
||||
// This also gets called at build time
|
||||
export async function getStaticProps({ params }) {
|
||||
// params contains the post `id`.
|
||||
// If the route is like /posts/1, then params.id is 1
|
||||
const res = await fetch(`https://.../posts/${params.id}`)
|
||||
const post = await res.json()
|
||||
|
||||
// Pass post data to the page via props
|
||||
return {
|
||||
props: { post },
|
||||
// Re-generate the post at most once per second
|
||||
// if a request comes in
|
||||
revalidate: 1,
|
||||
}
|
||||
}
|
||||
|
||||
export default Post
|
||||
```
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Changes |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `v13.4.0` | [App Router](/docs/app/getting-started/fetching-data) is now stable with simplified data fetching, including [`generateStaticParams()`](/docs/app/api-reference/functions/generate-static-params) |
|
||||
| `v12.2.0` | [On-Demand Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration#on-demand-revalidation-with-revalidatepath) is stable. |
|
||||
| `v12.1.0` | [On-Demand Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration#on-demand-revalidation-with-revalidatepath) added (beta). |
|
||||
| `v9.5.0` | Stable [Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration) |
|
||||
| `v9.3.0` | `getStaticPaths` introduced. |
|
||||
Generated
Vendored
+229
@@ -0,0 +1,229 @@
|
||||
---
|
||||
title: getStaticProps
|
||||
description: API reference for `getStaticProps`. Learn how to use `getStaticProps` to generate static pages with Next.js.
|
||||
---
|
||||
|
||||
Exporting a function called `getStaticProps` will prerender a page at build time using the props returned from the function:
|
||||
|
||||
```tsx filename="pages/index.tsx" switcher
|
||||
import type { InferGetStaticPropsType, GetStaticProps } from 'next'
|
||||
|
||||
type Repo = {
|
||||
name: string
|
||||
stargazers_count: number
|
||||
}
|
||||
|
||||
export const getStaticProps = (async (context) => {
|
||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
||||
const repo = await res.json()
|
||||
return { props: { repo } }
|
||||
}) satisfies GetStaticProps<{
|
||||
repo: Repo
|
||||
}>
|
||||
|
||||
export default function Page({
|
||||
repo,
|
||||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||
return repo.stargazers_count
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/index.js" switcher
|
||||
export async function getStaticProps() {
|
||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
||||
const repo = await res.json()
|
||||
return { props: { repo } }
|
||||
}
|
||||
|
||||
export default function Page({ repo }) {
|
||||
return repo.stargazers_count
|
||||
}
|
||||
```
|
||||
|
||||
You can import modules in top-level scope for use in `getStaticProps`. Imports used will **not be bundled for the client-side**. This means you can write **server-side code directly in `getStaticProps`**, including fetching data from your database.
|
||||
|
||||
## Context parameter
|
||||
|
||||
The `context` parameter is an object containing the following keys:
|
||||
|
||||
| Name | Description |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `params` | Contains the route parameters for pages using [dynamic routes](/docs/pages/building-your-application/routing/dynamic-routes). For example, if the page name is `[id].js`, then `params` will look like `{ id: ... }`. You should use this together with `getStaticPaths`, which we'll explain later. |
|
||||
| `preview` | (Deprecated for `draftMode`) `preview` is `true` if the page is in the [Preview Mode](/docs/pages/guides/preview-mode) and `false` otherwise. |
|
||||
| `previewData` | (Deprecated for `draftMode`) The [preview](/docs/pages/guides/preview-mode) data set by `setPreviewData`. |
|
||||
| `draftMode` | `draftMode` is `true` if the page is in the [Draft Mode](/docs/pages/guides/draft-mode) and `false` otherwise. |
|
||||
| `locale` | Contains the active locale (if enabled). |
|
||||
| `locales` | Contains all supported locales (if enabled). |
|
||||
| `defaultLocale` | Contains the configured default locale (if enabled). |
|
||||
| `revalidateReason` | Provides a reason for why the function was called. Can be one of: "build" (run at build time), "stale" (revalidate period expired, or running in [development mode](/docs/pages/building-your-application/data-fetching/get-static-props#runs-on-every-request-in-development)), "on-demand" (triggered via [on-demand revalidation](/docs/pages/guides/incremental-static-regeneration#on-demand-revalidation-with-revalidatepath)) |
|
||||
|
||||
## getStaticProps return values
|
||||
|
||||
The `getStaticProps` function should return an object containing either `props`, `redirect`, or `notFound` followed by an **optional** `revalidate` property.
|
||||
|
||||
### `props`
|
||||
|
||||
The `props` object is a key-value pair, where each value is received by the page component. It should be a [serializable object](https://developer.mozilla.org/docs/Glossary/Serialization) so that any props passed, could be serialized with [`JSON.stringify`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).
|
||||
|
||||
```jsx
|
||||
export async function getStaticProps(context) {
|
||||
return {
|
||||
props: { message: `Next.js is awesome` }, // will be passed to the page component as props
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `revalidate`
|
||||
|
||||
The `revalidate` property is the amount in seconds after which a page re-generation can occur (defaults to `false` or no revalidation).
|
||||
|
||||
```js
|
||||
// This function gets called at build time on server-side.
|
||||
// It may be called again, on a serverless function, if
|
||||
// revalidation is enabled and a new request comes in
|
||||
export async function getStaticProps() {
|
||||
const res = await fetch('https://.../posts')
|
||||
const posts = await res.json()
|
||||
|
||||
return {
|
||||
props: {
|
||||
posts,
|
||||
},
|
||||
// Next.js will attempt to re-generate the page:
|
||||
// - When a request comes in
|
||||
// - At most once every 10 seconds
|
||||
revalidate: 10, // In seconds
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration).
|
||||
|
||||
The cache status of a page leveraging ISR can be determined by reading the value of the `x-nextjs-cache` response header. The possible values are the following:
|
||||
|
||||
- `MISS` - the path is not in the cache (occurs at most once, on the first visit)
|
||||
- `STALE` - the path is in the cache but exceeded the revalidate time so it will be updated in the background
|
||||
- `HIT` - the path is in the cache and has not exceeded the revalidate time
|
||||
|
||||
### `notFound`
|
||||
|
||||
The `notFound` boolean allows the page to return a `404` status and [404 Page](/docs/pages/building-your-application/routing/custom-error#404-page). With `notFound: true`, the page will return a `404` even if there was a successfully generated page before. This is meant to support use cases like user-generated content getting removed by its author. Note, `notFound` follows the same `revalidate` behavior [described here](#revalidate).
|
||||
|
||||
```js
|
||||
export async function getStaticProps(context) {
|
||||
const res = await fetch(`https://.../data`)
|
||||
const data = await res.json()
|
||||
|
||||
if (!data) {
|
||||
return {
|
||||
notFound: true,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: { data }, // will be passed to the page component as props
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**: `notFound` is not needed for [`fallback: false`](/docs/pages/api-reference/functions/get-static-paths#fallback-false) mode as only paths returned from `getStaticPaths` will be prerendered.
|
||||
|
||||
### `redirect`
|
||||
|
||||
The `redirect` object allows redirecting to internal or external resources. It should match the shape of `{ destination: string, permanent: boolean }`.
|
||||
|
||||
In some rare cases, you might need to assign a custom status code for older `HTTP` clients to properly redirect. In these cases, you can use the `statusCode` property instead of the `permanent` property, **but not both**. You can also set `basePath: false` similar to redirects in `next.config.js`.
|
||||
|
||||
```js
|
||||
export async function getStaticProps(context) {
|
||||
const res = await fetch(`https://...`)
|
||||
const data = await res.json()
|
||||
|
||||
if (!data) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/',
|
||||
permanent: false,
|
||||
// statusCode: 301
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: { data }, // will be passed to the page component as props
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the redirects are known at build-time, they should be added in [`next.config.js`](/docs/pages/api-reference/config/next-config-js/redirects) instead.
|
||||
|
||||
## Reading files: Use `process.cwd()`
|
||||
|
||||
Files can be read directly from the filesystem in `getStaticProps`.
|
||||
|
||||
In order to do so you have to get the full path to a file.
|
||||
|
||||
Since Next.js compiles your code into a separate directory you can't use `__dirname` as the path it returns will be different from the Pages Router.
|
||||
|
||||
Instead you can use `process.cwd()` which gives you the directory where Next.js is being executed.
|
||||
|
||||
```jsx
|
||||
import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
// posts will be populated at build time by getStaticProps()
|
||||
function Blog({ posts }) {
|
||||
return (
|
||||
<ul>
|
||||
{posts.map((post) => (
|
||||
<li>
|
||||
<h3>{post.filename}</h3>
|
||||
<p>{post.content}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
// This function gets called at build time on server-side.
|
||||
// It won't be called on client-side, so you can even do
|
||||
// direct database queries.
|
||||
export async function getStaticProps() {
|
||||
const postsDirectory = path.join(process.cwd(), 'posts')
|
||||
const filenames = await fs.readdir(postsDirectory)
|
||||
|
||||
const posts = filenames.map(async (filename) => {
|
||||
const filePath = path.join(postsDirectory, filename)
|
||||
const fileContents = await fs.readFile(filePath, 'utf8')
|
||||
|
||||
// Generally you would parse/transform the contents
|
||||
// For example you can transform markdown to HTML here
|
||||
|
||||
return {
|
||||
filename,
|
||||
content: fileContents,
|
||||
}
|
||||
})
|
||||
// By returning { props: { posts } }, the Blog component
|
||||
// will receive `posts` as a prop at build time
|
||||
return {
|
||||
props: {
|
||||
posts: await Promise.all(posts),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default Blog
|
||||
```
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Changes |
|
||||
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `v13.4.0` | [App Router](/docs/app/getting-started/fetching-data) is now stable with simplified data fetching |
|
||||
| `v12.2.0` | [On-Demand Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration#on-demand-revalidation-with-revalidatepath) is stable. |
|
||||
| `v12.1.0` | [On-Demand Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration#on-demand-revalidation-with-revalidatepath) added (beta). |
|
||||
| `v10.0.0` | `locale`, `locales`, `defaultLocale`, and `notFound` options added. |
|
||||
| `v10.0.0` | `fallback: 'blocking'` return option added. |
|
||||
| `v9.5.0` | Stable [Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration) |
|
||||
| `v9.3.0` | `getStaticProps` introduced. |
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Functions
|
||||
description: API Reference for Functions and Hooks in Pages Router.
|
||||
source: app/api-reference/functions
|
||||
---
|
||||
|
||||
{/* DO NOT EDIT. The content of this doc is generated from the source above. To edit the content of this page, navigate to the source page in your editor. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: NextRequest
|
||||
description: API Reference for NextRequest.
|
||||
source: app/api-reference/functions/next-request
|
||||
---
|
||||
|
||||
{/* DO NOT EDIT. The content of this doc is generated from the source above. To edit the content of this page, navigate to the source page in your editor. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: NextResponse
|
||||
description: API Reference for NextResponse.
|
||||
source: app/api-reference/functions/next-response
|
||||
---
|
||||
|
||||
{/* DO NOT EDIT. The content of this doc is generated from the source above. To edit the content of this page, navigate to the source page in your editor. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
---
|
||||
title: useParams
|
||||
description: API Reference for the useParams hook in the Pages Router.
|
||||
---
|
||||
|
||||
`useParams` is a hook that lets you read a route's [dynamic params](/docs/pages/building-your-application/routing/dynamic-routes) filled in by the current URL.
|
||||
|
||||
```tsx filename="pages/shop/[slug].tsx" switcher
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
export default function ShopPage() {
|
||||
const params = useParams<{ slug: string }>()
|
||||
|
||||
if (!params) {
|
||||
// Render fallback UI while params are not yet available
|
||||
return null
|
||||
}
|
||||
|
||||
// Route -> /shop/[slug]
|
||||
// URL -> /shop/shoes
|
||||
// `params` -> { slug: 'shoes' }
|
||||
return <>Shop: {params.slug}</>
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/shop/[slug].js" switcher
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
export default function ShopPage() {
|
||||
const params = useParams()
|
||||
|
||||
if (!params) {
|
||||
// Render fallback UI while params are not yet available
|
||||
return null
|
||||
}
|
||||
|
||||
// Route -> /shop/[slug]
|
||||
// URL -> /shop/shoes
|
||||
// `params` -> { slug: 'shoes' }
|
||||
return <>Shop: {params.slug}</>
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
```tsx
|
||||
const params = useParams()
|
||||
```
|
||||
|
||||
`useParams` does not take any parameters.
|
||||
|
||||
## Returns
|
||||
|
||||
`useParams` returns an object containing the current route's filled in [dynamic parameters](/docs/pages/building-your-application/routing/dynamic-routes), or `null` during [prerendering](#behavior-during-prerendering).
|
||||
|
||||
- Each property in the object is an active dynamic segment.
|
||||
- The property name is the segment's name, and the property value is what the segment is filled in with.
|
||||
- The property value will either be a `string` or array of `string`s depending on the [type of dynamic segment](/docs/pages/building-your-application/routing/dynamic-routes).
|
||||
- If the route contains no dynamic parameters, `useParams` returns an empty object.
|
||||
|
||||
For example:
|
||||
|
||||
| Route | URL | `useParams()` |
|
||||
| ---------------------------- | ----------- | ------------------------- |
|
||||
| `pages/shop/page.js` | `/shop` | `{}` |
|
||||
| `pages/shop/[slug].js` | `/shop/1` | `{ slug: '1' }` |
|
||||
| `pages/shop/[tag]/[item].js` | `/shop/1/2` | `{ tag: '1', item: '2' }` |
|
||||
| `pages/shop/[...slug].js` | `/shop/1/2` | `{ slug: ['1', '2'] }` |
|
||||
|
||||
> **Good to know**: `useParams` is a [React Hook](https://react.dev/learn#using-hooks) and cannot be used with classes.
|
||||
|
||||
## Behavior
|
||||
|
||||
### Behavior during prerendering
|
||||
|
||||
For pages that are [statically optimized](/docs/pages/building-your-application/rendering/automatic-static-optimization), `useParams` will return `null` on the initial render. After hydration, the value will be updated to the actual params once the router is ready.
|
||||
|
||||
This is because params cannot be known during static generation for dynamic routes.
|
||||
|
||||
```tsx filename="pages/shop/[slug].tsx" switcher
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
export default function ShopPage() {
|
||||
const params = useParams<{ slug: string }>()
|
||||
|
||||
if (!params) {
|
||||
// Return a fallback UI while params are loading
|
||||
// This prevents hydration mismatches
|
||||
return <ShopPageSkeleton />
|
||||
}
|
||||
|
||||
return <>Shop: {params.slug}</>
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/shop/[slug].js" switcher
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
export default function ShopPage() {
|
||||
const params = useParams()
|
||||
|
||||
if (!params) {
|
||||
// Return a fallback UI while params are loading
|
||||
// This prevents hydration mismatches
|
||||
return <ShopPageSkeleton />
|
||||
}
|
||||
|
||||
return <>Shop: {params.slug}</>
|
||||
}
|
||||
```
|
||||
|
||||
### Using with `getServerSideProps`
|
||||
|
||||
When using [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props), the page is server-rendered on each request and `useParams` will return the actual params immediately:
|
||||
|
||||
```tsx filename="pages/shop/[slug].tsx" switcher
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
export default function ShopPage() {
|
||||
const params = useParams<{ slug: string }>()
|
||||
|
||||
// With getServerSideProps, this fallback is never rendered because
|
||||
// params is always available on the server. However, keeping
|
||||
// the fallback allows this component to be reused on other pages
|
||||
// that may not use getServerSideProps.
|
||||
if (!params) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <>Shop: {params.slug}</>
|
||||
}
|
||||
|
||||
export async function getServerSideProps() {
|
||||
return { props: {} }
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/shop/[slug].js" switcher
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
export default function ShopPage() {
|
||||
const params = useParams()
|
||||
|
||||
// With getServerSideProps, this fallback is never rendered because
|
||||
// params is always available on the server. However, keeping
|
||||
// the fallback allows this component to be reused on other pages
|
||||
// that may not use getServerSideProps.
|
||||
if (!params) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <>Shop: {params.slug}</>
|
||||
}
|
||||
|
||||
export async function getServerSideProps() {
|
||||
return { props: {} }
|
||||
}
|
||||
```
|
||||
|
||||
### Comparison with `router.query`
|
||||
|
||||
`useParams` only returns the dynamic route parameters, whereas [`router.query`](/docs/pages/api-reference/functions/use-router#router-object) from `useRouter` includes both dynamic parameters and query string parameters.
|
||||
|
||||
```tsx filename="pages/shop/[slug].tsx" switcher
|
||||
import { useRouter } from 'next/router'
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
export default function ShopPage() {
|
||||
const router = useRouter()
|
||||
const params = useParams()
|
||||
|
||||
// URL -> /shop/shoes?color=red
|
||||
|
||||
// router.query -> { slug: 'shoes', color: 'red' }
|
||||
// params -> { slug: 'shoes' }
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/shop/[slug].js" switcher
|
||||
import { useRouter } from 'next/router'
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
export default function ShopPage() {
|
||||
const router = useRouter()
|
||||
const params = useParams()
|
||||
|
||||
// URL -> /shop/shoes?color=red
|
||||
|
||||
// router.query -> { slug: 'shoes', color: 'red' }
|
||||
// params -> { slug: 'shoes' }
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Sharing components with App Router
|
||||
|
||||
`useParams` from `next/navigation` works in both the Pages Router and App Router. This allows you to create shared components that work in either context:
|
||||
|
||||
```tsx filename="components/breadcrumb.tsx" switcher
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
// This component works in both pages/ and app/
|
||||
export function Breadcrumb() {
|
||||
const params = useParams<{ slug: string }>()
|
||||
|
||||
if (!params) {
|
||||
// Fallback for Pages Router during prerendering
|
||||
return <nav>Home / ...</nav>
|
||||
}
|
||||
|
||||
return <nav>Home / {params.slug}</nav>
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="components/breadcrumb.js" switcher
|
||||
import { useParams } from 'next/navigation'
|
||||
|
||||
// This component works in both pages/ and app/
|
||||
export function Breadcrumb() {
|
||||
const params = useParams()
|
||||
|
||||
if (!params) {
|
||||
// Fallback for Pages Router during prerendering
|
||||
return <nav>Home / ...</nav>
|
||||
}
|
||||
|
||||
return <nav>Home / {params.slug}</nav>
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**: When using this component in the App Router, `useParams` never returns `null`, so the fallback branch will not be rendered.
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Changes |
|
||||
| --------- | ----------------------- |
|
||||
| `v13.3.0` | `useParams` introduced. |
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: useReportWebVitals
|
||||
description: useReportWebVitals
|
||||
source: app/api-reference/functions/use-report-web-vitals
|
||||
---
|
||||
|
||||
{/* DO NOT EDIT. The content of this doc is generated from the source above. To edit the content of this page, navigate to the source page in your editor. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
|
||||
+588
@@ -0,0 +1,588 @@
|
||||
---
|
||||
title: useRouter
|
||||
description: Learn more about the API of the Next.js Router, and access the router instance in your page with the useRouter hook.
|
||||
---
|
||||
|
||||
If you want to access the [`router` object](#router-object) inside any function component in your app, you can use the `useRouter` hook, take a look at the following example:
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
function ActiveLink({ children, href }) {
|
||||
const router = useRouter()
|
||||
const style = {
|
||||
marginRight: 10,
|
||||
color: router.asPath === href ? 'red' : 'black',
|
||||
}
|
||||
|
||||
const handleClick = (e) => {
|
||||
e.preventDefault()
|
||||
router.push(href)
|
||||
}
|
||||
|
||||
return (
|
||||
<a href={href} onClick={handleClick} style={style}>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
export default ActiveLink
|
||||
```
|
||||
|
||||
> `useRouter` is a [React Hook](https://react.dev/learn#using-hooks), meaning it cannot be used with classes. You can either use [withRouter](#withrouter) or wrap your class in a function component.
|
||||
|
||||
## `router` object
|
||||
|
||||
The following is the definition of the `router` object returned by both [`useRouter`](#top) and [`withRouter`](#withrouter):
|
||||
|
||||
- `pathname`: `String` - The path for current route file that comes after `/pages`. Therefore, `basePath`, `locale` and trailing slash (`trailingSlash: true`) are not included.
|
||||
- `query`: `Object` - The query string parsed to an object, including [dynamic route](/docs/pages/building-your-application/routing/dynamic-routes) parameters. It will be an empty object during prerendering if the page doesn't use [Server-side Rendering](/docs/pages/building-your-application/data-fetching/get-server-side-props). Defaults to `{}`
|
||||
- `asPath`: `String` - The path as shown in the browser including the search params and respecting the `trailingSlash` configuration. `basePath` and `locale` are not included.
|
||||
- `isFallback`: `boolean` - Whether the current page is in [fallback mode](/docs/pages/api-reference/functions/get-static-paths#fallback-true).
|
||||
- `basePath`: `String` - The active [basePath](/docs/app/api-reference/config/next-config-js/basePath) (if enabled).
|
||||
- `locale`: `String` - The active locale (if enabled).
|
||||
- `locales`: `String[]` - All supported locales (if enabled).
|
||||
- `defaultLocale`: `String` - The current default locale (if enabled).
|
||||
- `domainLocales`: `Array<{domain, defaultLocale, locales}>` - Any configured domain locales.
|
||||
- `isReady`: `boolean` - Whether the router fields are updated client-side and ready for use. Should only be used inside of `useEffect` methods and not for conditionally rendering on the server. See related docs for use case with [automatically statically optimized pages](/docs/pages/building-your-application/rendering/automatic-static-optimization)
|
||||
- `isPreview`: `boolean` - Whether the application is currently in [preview mode](/docs/pages/guides/preview-mode).
|
||||
|
||||
> Using the `asPath` field may lead to a mismatch between client and server if the page is rendered using server-side rendering or [automatic static optimization](/docs/pages/building-your-application/rendering/automatic-static-optimization). Avoid using `asPath` until the `isReady` field is `true`.
|
||||
|
||||
The following methods are included inside `router`:
|
||||
|
||||
### router.push
|
||||
|
||||
Handles client-side transitions, this method is useful for cases where [`next/link`](/docs/pages/api-reference/components/link) is not enough.
|
||||
|
||||
```js
|
||||
router.push(url, as, options)
|
||||
```
|
||||
|
||||
- `url`: `UrlObject | String` - The URL to navigate to (see [Node.JS URL module documentation](https://nodejs.org/api/url.html#legacy-urlobject) for `UrlObject` properties).
|
||||
- `as`: `UrlObject | String` - Optional decorator for the path that will be shown in the browser URL bar. Before Next.js 9.5.3 this was used for dynamic routes.
|
||||
- `options` - Optional object with the following configuration options:
|
||||
- `scroll` - Optional boolean, controls scrolling to the top of the page after navigation. Defaults to `true`
|
||||
- [`shallow`](/docs/pages/building-your-application/routing/linking-and-navigating#shallow-routing): Update the path of the current page without rerunning [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props), [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props) or [`getInitialProps`](/docs/pages/api-reference/functions/get-initial-props). Defaults to `false`
|
||||
- `locale` - Optional string, indicates locale of the new page
|
||||
|
||||
> You don't need to use `router.push` for external URLs. [window.location](https://developer.mozilla.org/docs/Web/API/Window/location) is better suited for those cases.
|
||||
|
||||
Navigating to `pages/about.js`, which is a predefined route:
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<button type="button" onClick={() => router.push('/about')}>
|
||||
Click me
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Navigating `pages/post/[pid].js`, which is a dynamic route:
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<button type="button" onClick={() => router.push('/post/abc')}>
|
||||
Click me
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Redirecting the user to `pages/login.js`, useful for pages behind [authentication](/docs/pages/guides/authentication):
|
||||
|
||||
```jsx
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
// Here you would fetch and return the user
|
||||
const useUser = () => ({ user: null, loading: false })
|
||||
|
||||
export default function Page() {
|
||||
const { user, loading } = useUser()
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
if (!(user || loading)) {
|
||||
router.push('/login')
|
||||
}
|
||||
}, [user, loading])
|
||||
|
||||
return <p>Redirecting...</p>
|
||||
}
|
||||
```
|
||||
|
||||
#### Resetting state after navigation
|
||||
|
||||
When navigating to the same page in Next.js, the page's state **will not** be reset by default as React does not unmount unless the parent component has changed.
|
||||
|
||||
```jsx filename="pages/[slug].js"
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter()
|
||||
const [count, setCount] = useState(0)
|
||||
return (
|
||||
<div>
|
||||
<h1>Page: {router.query.slug}</h1>
|
||||
<p>Count: {count}</p>
|
||||
<button onClick={() => setCount(count + 1)}>Increase count</button>
|
||||
<Link href="/one">one</Link> <Link href="/two">two</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, navigating between `/one` and `/two` **will not** reset the count . The `useState` is maintained between renders because the top-level React component, `Page`, is the same.
|
||||
|
||||
If you do not want this behavior, you have a couple of options:
|
||||
|
||||
- Manually ensure each state is updated using `useEffect`. In the above example, that could look like:
|
||||
|
||||
```jsx
|
||||
useEffect(() => {
|
||||
setCount(0)
|
||||
}, [router.query.slug])
|
||||
```
|
||||
|
||||
- Use a React `key` to [tell React to remount the component](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key). To do this for all pages, you can use a custom app:
|
||||
|
||||
```jsx filename="pages/_app.js"
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
const router = useRouter()
|
||||
return <Component key={router.asPath} {...pageProps} />
|
||||
}
|
||||
```
|
||||
|
||||
#### With URL object
|
||||
|
||||
You can use a URL object in the same way you can use it for [`next/link`](/docs/pages/api-reference/components/link#passing-a-url-object). Works for both the `url` and `as` parameters:
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function ReadMore({ post }) {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
router.push({
|
||||
pathname: '/post/[pid]',
|
||||
query: { pid: post.id },
|
||||
})
|
||||
}}
|
||||
>
|
||||
Click here to read more
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### router.replace
|
||||
|
||||
Similar to the `replace` prop in [`next/link`](/docs/pages/api-reference/components/link), `router.replace` will prevent adding a new URL entry into the `history` stack.
|
||||
|
||||
```js
|
||||
router.replace(url, as, options)
|
||||
```
|
||||
|
||||
- The API for `router.replace` is exactly the same as the API for [`router.push`](#routerpush).
|
||||
|
||||
Take a look at the following example:
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<button type="button" onClick={() => router.replace('/home')}>
|
||||
Click me
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### router.prefetch
|
||||
|
||||
Prefetch pages for faster client-side transitions. This method is only useful for navigations without [`next/link`](/docs/pages/api-reference/components/link), as `next/link` takes care of prefetching pages automatically.
|
||||
|
||||
> This is a production only feature. Next.js doesn't prefetch pages in development.
|
||||
|
||||
```js
|
||||
router.prefetch(url, as, options)
|
||||
```
|
||||
|
||||
- `url` - The URL to prefetch, including explicit routes (e.g. `/dashboard`) and dynamic routes (e.g. `/product/[id]`)
|
||||
- `as` - Optional decorator for `url`. Before Next.js 9.5.3 this was used to prefetch dynamic routes.
|
||||
- `options` - Optional object with the following allowed fields:
|
||||
- `locale` - allows providing a different locale from the active one. If `false`, `url` has to include the locale as the active locale won't be used.
|
||||
|
||||
Let's say you have a login page, and after a login, you redirect the user to the dashboard. For that case, we can prefetch the dashboard to make a faster transition, like in the following example:
|
||||
|
||||
```jsx
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Login() {
|
||||
const router = useRouter()
|
||||
const handleSubmit = useCallback((e) => {
|
||||
e.preventDefault()
|
||||
|
||||
fetch('/api/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
/* Form data */
|
||||
}),
|
||||
}).then((res) => {
|
||||
// Do a fast client-side transition to the already prefetched dashboard page
|
||||
if (res.ok) router.push('/dashboard')
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// Prefetch the dashboard page
|
||||
router.prefetch('/dashboard')
|
||||
}, [router])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
{/* Form fields */}
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### router.beforePopState
|
||||
|
||||
In some cases (for example, if using a [Custom Server](/docs/pages/guides/custom-server)), you may wish to listen to [popstate](https://developer.mozilla.org/docs/Web/API/Window/popstate_event) and do something before the router acts on it.
|
||||
|
||||
```js
|
||||
router.beforePopState(cb)
|
||||
```
|
||||
|
||||
- `cb` - The function to run on incoming `popstate` events. The function receives the state of the event as an object with the following props:
|
||||
- `url`: `String` - the route for the new state. This is usually the name of a `page`
|
||||
- `as`: `String` - the url that will be shown in the browser
|
||||
- `options`: `Object` - Additional options sent by [router.push](#routerpush)
|
||||
|
||||
If `cb` returns `false`, the Next.js router will not handle `popstate`, and you'll be responsible for handling it in that case. See [Disabling file-system routing](/docs/pages/guides/custom-server#disabling-file-system-routing).
|
||||
|
||||
You could use `beforePopState` to manipulate the request, or force a SSR refresh, as in the following example:
|
||||
|
||||
```jsx
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
router.beforePopState(({ url, as, options }) => {
|
||||
// I only want to allow these two routes!
|
||||
if (as !== '/' && as !== '/other') {
|
||||
// Have SSR render bad routes as a 404.
|
||||
window.location.href = as
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}, [router])
|
||||
|
||||
return <p>Welcome to the page</p>
|
||||
}
|
||||
```
|
||||
|
||||
### router.back
|
||||
|
||||
Navigate back in history. Equivalent to clicking the browser’s back button. It executes `window.history.back()`.
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<button type="button" onClick={() => router.back()}>
|
||||
Click here to go back
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### router.reload
|
||||
|
||||
Reload the current URL. Equivalent to clicking the browser’s refresh button. It executes `window.location.reload()`.
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<button type="button" onClick={() => router.reload()}>
|
||||
Click here to reload
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### router.events
|
||||
|
||||
You can listen to different events happening inside the Next.js Router. Here's a list of supported events:
|
||||
|
||||
- `routeChangeStart(url, { shallow })` - Fires when a route starts to change
|
||||
- `routeChangeComplete(url, { shallow })` - Fires when a route changed completely
|
||||
- `routeChangeError(err, url, { shallow })` - Fires when there's an error when changing routes, or a route load is cancelled
|
||||
- `err.cancelled` - Indicates if the navigation was cancelled
|
||||
- `beforeHistoryChange(url, { shallow })` - Fires before changing the browser's history
|
||||
- `hashChangeStart(url, { shallow })` - Fires when the hash will change but not the page
|
||||
- `hashChangeComplete(url, { shallow })` - Fires when the hash has changed but not the page
|
||||
|
||||
> **Good to know**: Here `url` is the URL shown in the browser, including the [`basePath`](/docs/app/api-reference/config/next-config-js/basePath).
|
||||
|
||||
For example, to listen to the router event `routeChangeStart`, open or create `pages/_app.js` and subscribe to the event, like so:
|
||||
|
||||
```jsx
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
const handleRouteChange = (url, { shallow }) => {
|
||||
console.log(
|
||||
`App is changing to ${url} ${
|
||||
shallow ? 'with' : 'without'
|
||||
} shallow routing`
|
||||
)
|
||||
}
|
||||
|
||||
router.events.on('routeChangeStart', handleRouteChange)
|
||||
|
||||
// If the component is unmounted, unsubscribe
|
||||
// from the event with the `off` method:
|
||||
return () => {
|
||||
router.events.off('routeChangeStart', handleRouteChange)
|
||||
}
|
||||
}, [router])
|
||||
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
```
|
||||
|
||||
> We use a [Custom App](/docs/pages/building-your-application/routing/custom-app) (`pages/_app.js`) for this example to subscribe to the event because it's not unmounted on page navigations, but you can subscribe to router events on any component in your application.
|
||||
|
||||
Router events should be registered when a component mounts ([useEffect](https://react.dev/reference/react/useEffect) or [componentDidMount](https://react.dev/reference/react/Component#componentdidmount) / [componentWillUnmount](https://react.dev/reference/react/Component#componentwillunmount)) or imperatively when an event happens.
|
||||
|
||||
If a route load is cancelled (for example, by clicking two links rapidly in succession), `routeChangeError` will fire. And the passed `err` will contain a `cancelled` property set to `true`, as in the following example:
|
||||
|
||||
```jsx
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
const handleRouteChangeError = (err, url) => {
|
||||
if (err.cancelled) {
|
||||
console.log(`Route to ${url} was cancelled!`)
|
||||
}
|
||||
}
|
||||
|
||||
router.events.on('routeChangeError', handleRouteChangeError)
|
||||
|
||||
// If the component is unmounted, unsubscribe
|
||||
// from the event with the `off` method:
|
||||
return () => {
|
||||
router.events.off('routeChangeError', handleRouteChangeError)
|
||||
}
|
||||
}, [router])
|
||||
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
```
|
||||
|
||||
## The `next/compat/router` export
|
||||
|
||||
This is the same `useRouter` hook, but can be used in both `app` and `pages` directories.
|
||||
|
||||
It differs from `next/router` in that it does not throw an error when the pages router is not mounted, and instead has a return type of `NextRouter | null`.
|
||||
This allows developers to convert components to support running in both `app` and `pages` as they transition to the `app` router.
|
||||
|
||||
A component that previously looked like this:
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
const MyComponent = () => {
|
||||
const { isReady, query } = useRouter()
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Will error when converted over to `next/compat/router`, as `null` cannot be destructured. Instead, developers will be able to take advantage of new hooks:
|
||||
|
||||
```jsx
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/compat/router'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
const MyComponent = () => {
|
||||
const router = useRouter() // may be null or a NextRouter instance
|
||||
const searchParams = useSearchParams()
|
||||
useEffect(() => {
|
||||
if (router && !router.isReady) {
|
||||
return
|
||||
}
|
||||
// In `app/`, searchParams will be ready immediately with the values, in
|
||||
// `pages/` it will be available after the router is ready.
|
||||
const search = searchParams.get('search')
|
||||
// ...
|
||||
}, [router, searchParams])
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
This component will now work in both `pages` and `app` directories. When the component is no longer used in `pages`, you can remove the references to the compat router:
|
||||
|
||||
```jsx
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
const MyComponent = () => {
|
||||
const searchParams = useSearchParams()
|
||||
// As this component is only used in `app/`, the compat router can be removed.
|
||||
const search = searchParams.get('search')
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Using `useRouter` outside of Next.js context in pages
|
||||
|
||||
Another specific use case is when rendering components outside of a Next.js application context, such as inside `getServerSideProps` on the `pages` directory. In this case, the compat router can be used to avoid errors:
|
||||
|
||||
```jsx
|
||||
import { renderToString } from 'react-dom/server'
|
||||
import { useRouter } from 'next/compat/router'
|
||||
const MyComponent = () => {
|
||||
const router = useRouter() // may be null or a NextRouter instance
|
||||
// ...
|
||||
}
|
||||
export async function getServerSideProps() {
|
||||
const renderedComponent = renderToString(<MyComponent />)
|
||||
return {
|
||||
props: {
|
||||
renderedComponent,
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Potential ESLint errors
|
||||
|
||||
Certain methods accessible on the `router` object return a Promise. If you have the ESLint rule, [no-floating-promises](https://typescript-eslint.io/rules/no-floating-promises) enabled, consider disabling it either globally, or for the affected line.
|
||||
|
||||
If your application needs this rule, you should either `void` the promise – or use an `async` function, `await` the Promise, then void the function call. **This is not applicable when the method is called from inside an `onClick` handler**.
|
||||
|
||||
The affected methods are:
|
||||
|
||||
- `router.push`
|
||||
- `router.replace`
|
||||
- `router.prefetch`
|
||||
|
||||
### Potential solutions
|
||||
|
||||
```jsx
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
// Here you would fetch and return the user
|
||||
const useUser = () => ({ user: null, loading: false })
|
||||
|
||||
export default function Page() {
|
||||
const { user, loading } = useUser()
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
// disable the linting on the next line - This is the cleanest solution
|
||||
// eslint-disable-next-line no-floating-promises
|
||||
router.push('/login')
|
||||
|
||||
// void the Promise returned by router.push
|
||||
if (!(user || loading)) {
|
||||
void router.push('/login')
|
||||
}
|
||||
// or use an async function, await the Promise, then void the function call
|
||||
async function handleRouteChange() {
|
||||
if (!(user || loading)) {
|
||||
await router.push('/login')
|
||||
}
|
||||
}
|
||||
void handleRouteChange()
|
||||
}, [user, loading])
|
||||
|
||||
return <p>Redirecting...</p>
|
||||
}
|
||||
```
|
||||
|
||||
## withRouter
|
||||
|
||||
If [`useRouter`](#router-object) is not the best fit for you, `withRouter` can also add the same [`router` object](#router-object) to any component.
|
||||
|
||||
### Usage
|
||||
|
||||
```jsx
|
||||
import { withRouter } from 'next/router'
|
||||
|
||||
function Page({ router }) {
|
||||
return <p>{router.pathname}</p>
|
||||
}
|
||||
|
||||
export default withRouter(Page)
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
To use class components with `withRouter`, the component needs to accept a router prop:
|
||||
|
||||
```tsx
|
||||
import React from 'react'
|
||||
import { withRouter, NextRouter } from 'next/router'
|
||||
|
||||
interface WithRouterProps {
|
||||
router: NextRouter
|
||||
}
|
||||
|
||||
interface MyComponentProps extends WithRouterProps {}
|
||||
|
||||
class MyComponent extends React.Component<MyComponentProps> {
|
||||
render() {
|
||||
return <p>{this.props.router.pathname}</p>
|
||||
}
|
||||
}
|
||||
|
||||
export default withRouter(MyComponent)
|
||||
```
|
||||
Generated
Vendored
+318
@@ -0,0 +1,318 @@
|
||||
---
|
||||
title: useSearchParams
|
||||
description: API Reference for the useSearchParams hook in the Pages Router.
|
||||
---
|
||||
|
||||
`useSearchParams` is a hook that lets you read the current URL's **query string**.
|
||||
|
||||
`useSearchParams` returns a **read-only** version of the [`URLSearchParams`](https://developer.mozilla.org/docs/Web/API/URLSearchParams) interface.
|
||||
|
||||
```tsx filename="pages/dashboard.tsx" switcher
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
export default function Dashboard() {
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
if (!searchParams) {
|
||||
// Render fallback UI while search params are not yet available
|
||||
return null
|
||||
}
|
||||
|
||||
const search = searchParams.get('search')
|
||||
|
||||
// URL -> `/dashboard?search=my-project`
|
||||
// `search` -> 'my-project'
|
||||
return <>Search: {search}</>
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/dashboard.js" switcher
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
export default function Dashboard() {
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
if (!searchParams) {
|
||||
// Render fallback UI while search params are not yet available
|
||||
return null
|
||||
}
|
||||
|
||||
const search = searchParams.get('search')
|
||||
|
||||
// URL -> `/dashboard?search=my-project`
|
||||
// `search` -> 'my-project'
|
||||
return <>Search: {search}</>
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
```tsx
|
||||
const searchParams = useSearchParams()
|
||||
```
|
||||
|
||||
`useSearchParams` does not take any parameters.
|
||||
|
||||
## Returns
|
||||
|
||||
`useSearchParams` returns a **read-only** version of the [`URLSearchParams`](https://developer.mozilla.org/docs/Web/API/URLSearchParams) interface, or `null` during [prerendering](#behavior-during-prerendering).
|
||||
|
||||
The interface includes utility methods for reading the URL's query string:
|
||||
|
||||
- [`URLSearchParams.get()`](https://developer.mozilla.org/docs/Web/API/URLSearchParams/get): Returns the first value associated with the search parameter. For example:
|
||||
|
||||
| URL | `searchParams.get("a")` |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
|
||||
| `/dashboard?a=1` | `'1'` |
|
||||
| `/dashboard?a=` | `''` |
|
||||
| `/dashboard?b=3` | `null` |
|
||||
| `/dashboard?a=1&a=2` | `'1'` _- use [`getAll()`](https://developer.mozilla.org/docs/Web/API/URLSearchParams/getAll) to get all values_ |
|
||||
|
||||
- [`URLSearchParams.has()`](https://developer.mozilla.org/docs/Web/API/URLSearchParams/has): Returns a boolean value indicating if the given parameter exists. For example:
|
||||
|
||||
| URL | `searchParams.has("a")` |
|
||||
| ---------------- | ----------------------- |
|
||||
| `/dashboard?a=1` | `true` |
|
||||
| `/dashboard?b=3` | `false` |
|
||||
|
||||
- Learn more about other **read-only** methods of [`URLSearchParams`](https://developer.mozilla.org/docs/Web/API/URLSearchParams), including the [`getAll()`](https://developer.mozilla.org/docs/Web/API/URLSearchParams/getAll), [`keys()`](https://developer.mozilla.org/docs/Web/API/URLSearchParams/keys), [`values()`](https://developer.mozilla.org/docs/Web/API/URLSearchParams/values), [`entries()`](https://developer.mozilla.org/docs/Web/API/URLSearchParams/entries), [`forEach()`](https://developer.mozilla.org/docs/Web/API/URLSearchParams/forEach), and [`toString()`](https://developer.mozilla.org/docs/Web/API/URLSearchParams/toString).
|
||||
|
||||
> **Good to know**: `useSearchParams` is a [React Hook](https://react.dev/learn#using-hooks) and cannot be used with classes.
|
||||
|
||||
## Behavior
|
||||
|
||||
### Behavior during prerendering
|
||||
|
||||
For pages that are [statically optimized](/docs/pages/building-your-application/rendering/automatic-static-optimization) (not using `getServerSideProps`), `useSearchParams` will return `null` during prerendering. After hydration, the value will be updated to the actual search params.
|
||||
|
||||
This is because search params cannot be known during static generation as they depend on the request.
|
||||
|
||||
```tsx filename="pages/dashboard.tsx" switcher
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
export default function Dashboard() {
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
if (!searchParams) {
|
||||
// Return a fallback UI while search params are loading
|
||||
// This prevents hydration mismatches
|
||||
return <DashboardSkeleton />
|
||||
}
|
||||
|
||||
const search = searchParams.get('search')
|
||||
|
||||
return <>Search: {search}</>
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/dashboard.js" switcher
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
export default function Dashboard() {
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
if (!searchParams) {
|
||||
// Return a fallback UI while search params are loading
|
||||
// This prevents hydration mismatches
|
||||
return <DashboardSkeleton />
|
||||
}
|
||||
|
||||
const search = searchParams.get('search')
|
||||
|
||||
return <>Search: {search}</>
|
||||
}
|
||||
```
|
||||
|
||||
### Using with `getServerSideProps`
|
||||
|
||||
When using [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props), the page is server-rendered on each request and `useSearchParams` will return the actual search params immediately:
|
||||
|
||||
```tsx filename="pages/dashboard.tsx" switcher
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
export default function Dashboard() {
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
// With getServerSideProps, this fallback is never rendered because
|
||||
// searchParams is always available on the server. However, keeping
|
||||
// the fallback allows this component to be reused on other pages
|
||||
// that may not use getServerSideProps.
|
||||
if (!searchParams) {
|
||||
return null
|
||||
}
|
||||
|
||||
const search = searchParams.get('search')
|
||||
|
||||
return <>Search: {search}</>
|
||||
}
|
||||
|
||||
export async function getServerSideProps() {
|
||||
return { props: {} }
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/dashboard.js" switcher
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
export default function Dashboard() {
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
// With getServerSideProps, this fallback is never rendered because
|
||||
// searchParams is always available on the server. However, keeping
|
||||
// the fallback allows this component to be reused on other pages
|
||||
// that may not use getServerSideProps.
|
||||
if (!searchParams) {
|
||||
return null
|
||||
}
|
||||
|
||||
const search = searchParams.get('search')
|
||||
|
||||
return <>Search: {search}</>
|
||||
}
|
||||
|
||||
export async function getServerSideProps() {
|
||||
return { props: {} }
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Updating search params
|
||||
|
||||
You can use the [`useRouter`](/docs/pages/api-reference/functions/use-router) hook to update search params:
|
||||
|
||||
```tsx filename="pages/dashboard.tsx" switcher
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
export default function Dashboard() {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
const createQueryString = useCallback(
|
||||
(name: string, value: string) => {
|
||||
const params = new URLSearchParams(searchParams?.toString())
|
||||
params.set(name, value)
|
||||
return params.toString()
|
||||
},
|
||||
[searchParams]
|
||||
)
|
||||
|
||||
if (!searchParams) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>Sort By</p>
|
||||
<button
|
||||
onClick={() => {
|
||||
router.push(router.pathname + '?' + createQueryString('sort', 'asc'))
|
||||
}}
|
||||
>
|
||||
ASC
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
router.push(router.pathname + '?' + createQueryString('sort', 'desc'))
|
||||
}}
|
||||
>
|
||||
DESC
|
||||
</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/dashboard.js" switcher
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
export default function Dashboard() {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
const createQueryString = useCallback(
|
||||
(name, value) => {
|
||||
const params = new URLSearchParams(searchParams?.toString())
|
||||
params.set(name, value)
|
||||
return params.toString()
|
||||
},
|
||||
[searchParams]
|
||||
)
|
||||
|
||||
if (!searchParams) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>Sort By</p>
|
||||
<button
|
||||
onClick={() => {
|
||||
router.push(router.pathname + '?' + createQueryString('sort', 'asc'))
|
||||
}}
|
||||
>
|
||||
ASC
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
router.push(router.pathname + '?' + createQueryString('sort', 'desc'))
|
||||
}}
|
||||
>
|
||||
DESC
|
||||
</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Sharing components with App Router
|
||||
|
||||
`useSearchParams` from `next/navigation` works in both the Pages Router and App Router. This allows you to create shared components that work in either context:
|
||||
|
||||
```tsx filename="components/search-bar.tsx" switcher
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
// This component works in both pages/ and app/
|
||||
export function SearchBar() {
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
if (!searchParams) {
|
||||
// Fallback for Pages Router during prerendering
|
||||
return <input defaultValue="" placeholder="Search..." />
|
||||
}
|
||||
|
||||
const search = searchParams.get('search') ?? ''
|
||||
|
||||
return <input defaultValue={search} placeholder="Search..." />
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="components/search-bar.js" switcher
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
// This component works in both pages/ and app/
|
||||
export function SearchBar() {
|
||||
const searchParams = useSearchParams()
|
||||
|
||||
if (!searchParams) {
|
||||
// Fallback for Pages Router during prerendering
|
||||
return <input defaultValue="" placeholder="Search..." />
|
||||
}
|
||||
|
||||
const search = searchParams.get('search') ?? ''
|
||||
|
||||
return <input defaultValue={search} placeholder="Search..." />
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**: When using this component in the App Router, wrap it in a `<Suspense>` boundary for [prerendering](/docs/app/api-reference/functions/use-search-params#prerendering) support.
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Changes |
|
||||
| --------- | ----------------------------- |
|
||||
| `v13.0.0` | `useSearchParams` introduced. |
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: userAgent
|
||||
description: The userAgent helper extends the Web Request API with additional properties and methods to interact with the user agent object from the request.
|
||||
source: app/api-reference/functions/userAgent
|
||||
---
|
||||
|
||||
{/* DO NOT EDIT. The content of this doc is generated from the source above. To edit the content of this page, navigate to the source page in your editor. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
|
||||
Reference in New Issue
Block a user