.
This commit is contained in:
node_modules/next/dist/docs/02-pages/03-building-your-application/01-routing/01-pages-and-layouts.md
Generated
Vendored
+213
@@ -0,0 +1,213 @@
|
||||
---
|
||||
title: Pages and Layouts
|
||||
description: Create your first page and shared layout with the Pages Router.
|
||||
---
|
||||
|
||||
The Pages Router has a file-system based router built on the concept of pages.
|
||||
|
||||
When a file is added to the `pages` directory, it's automatically available as a route.
|
||||
|
||||
In Next.js, a **page** is a [React Component](https://react.dev/learn/your-first-component) exported from a `.js`, `.jsx`, `.ts`, or `.tsx` file in the `pages` directory. Each page is associated with a route based on its file name.
|
||||
|
||||
**Example**: If you create `pages/about.js` that exports a React component like below, it will be accessible at `/about`.
|
||||
|
||||
```jsx
|
||||
export default function About() {
|
||||
return <div>About</div>
|
||||
}
|
||||
```
|
||||
|
||||
## Index routes
|
||||
|
||||
The router will automatically route files named `index` to the root of the directory.
|
||||
|
||||
- `pages/index.js` → `/`
|
||||
- `pages/blog/index.js` → `/blog`
|
||||
|
||||
## Nested routes
|
||||
|
||||
The router supports nested files. If you create a nested folder structure, files will automatically be routed in the same way still.
|
||||
|
||||
- `pages/blog/first-post.js` → `/blog/first-post`
|
||||
- `pages/dashboard/settings/username.js` → `/dashboard/settings/username`
|
||||
|
||||
## Pages with Dynamic Routes
|
||||
|
||||
Next.js supports pages with dynamic routes. For example, if you create a file called `pages/posts/[id].js`, then it will be accessible at `posts/1`, `posts/2`, etc.
|
||||
|
||||
> To learn more about dynamic routing, check the [Dynamic Routing documentation](/docs/pages/building-your-application/routing/dynamic-routes).
|
||||
|
||||
## Layout Pattern
|
||||
|
||||
The React model allows us to deconstruct a [page](/docs/pages/building-your-application/routing/pages-and-layouts) into a series of components. Many of these components are often reused between pages. For example, you might have the same navigation bar and footer on every page.
|
||||
|
||||
```jsx filename="components/layout.js"
|
||||
import Navbar from './navbar'
|
||||
import Footer from './footer'
|
||||
|
||||
export default function Layout({ children }) {
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
<main>{children}</main>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Single Shared Layout with Custom App
|
||||
|
||||
If you only have one layout for your entire application, you can create a [Custom App](/docs/pages/building-your-application/routing/custom-app) and wrap your application with the layout. Since the `<Layout />` component is re-used when changing pages, its component state will be preserved (e.g. input values).
|
||||
|
||||
```jsx filename="pages/_app.js"
|
||||
import Layout from '../components/layout'
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<Layout>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Per-Page Layouts
|
||||
|
||||
If you need multiple layouts, you can add a property `getLayout` to your page, allowing you to return a React component for the layout. This allows you to define the layout on a _per-page basis_. Since we're returning a function, we can have complex nested layouts if desired.
|
||||
|
||||
```jsx filename="pages/index.js"
|
||||
|
||||
import Layout from '../components/layout'
|
||||
import NestedLayout from '../components/nested-layout'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
/** Your content */
|
||||
)
|
||||
}
|
||||
|
||||
Page.getLayout = function getLayout(page) {
|
||||
return (
|
||||
<Layout>
|
||||
<NestedLayout>{page}</NestedLayout>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/_app.js"
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
// Use the layout defined at the page level, if available
|
||||
const getLayout = Component.getLayout ?? ((page) => page)
|
||||
|
||||
return getLayout(<Component {...pageProps} />)
|
||||
}
|
||||
```
|
||||
|
||||
When navigating between pages, we want to _persist_ page state (input values, scroll position, etc.) for a Single-Page Application (SPA) experience.
|
||||
|
||||
This layout pattern enables state persistence because the React component tree is maintained between page transitions. With the component tree, React can understand which elements have changed to preserve state.
|
||||
|
||||
> **Good to know**: This process is called [reconciliation](https://react.dev/learn/preserving-and-resetting-state), which is how React understands which elements have changed.
|
||||
|
||||
### With TypeScript
|
||||
|
||||
When using TypeScript, you must first create a new type for your pages which includes a `getLayout` function. Then, you must create a new type for your `AppProps` which overrides the `Component` property to use the previously created type.
|
||||
|
||||
```tsx filename="pages/index.tsx" switcher
|
||||
import type { ReactElement } from 'react'
|
||||
import Layout from '../components/layout'
|
||||
import NestedLayout from '../components/nested-layout'
|
||||
import type { NextPageWithLayout } from './_app'
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
return <p>hello world</p>
|
||||
}
|
||||
|
||||
Page.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<Layout>
|
||||
<NestedLayout>{page}</NestedLayout>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
||||
```
|
||||
|
||||
```jsx filename="pages/index.js" switcher
|
||||
import Layout from '../components/layout'
|
||||
import NestedLayout from '../components/nested-layout'
|
||||
|
||||
const Page = () => {
|
||||
return <p>hello world</p>
|
||||
}
|
||||
|
||||
Page.getLayout = function getLayout(page) {
|
||||
return (
|
||||
<Layout>
|
||||
<NestedLayout>{page}</NestedLayout>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
||||
```
|
||||
|
||||
```tsx filename="pages/_app.tsx" switcher
|
||||
import type { ReactElement, ReactNode } from 'react'
|
||||
import type { NextPage } from 'next'
|
||||
import type { AppProps } from 'next/app'
|
||||
|
||||
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
||||
getLayout?: (page: ReactElement) => ReactNode
|
||||
}
|
||||
|
||||
type AppPropsWithLayout = AppProps & {
|
||||
Component: NextPageWithLayout
|
||||
}
|
||||
|
||||
export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
// Use the layout defined at the page level, if available
|
||||
const getLayout = Component.getLayout ?? ((page) => page)
|
||||
|
||||
return getLayout(<Component {...pageProps} />)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/_app.js" switcher
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
// Use the layout defined at the page level, if available
|
||||
const getLayout = Component.getLayout ?? ((page) => page)
|
||||
|
||||
return getLayout(<Component {...pageProps} />)
|
||||
}
|
||||
```
|
||||
|
||||
### Data Fetching
|
||||
|
||||
Inside your layout, you can fetch data on the client-side using `useEffect` or a library like [SWR](https://swr.vercel.app/). Because this file is not a [Page](/docs/pages/building-your-application/routing/pages-and-layouts), you cannot use `getStaticProps` or `getServerSideProps` currently.
|
||||
|
||||
```jsx filename="components/layout.js"
|
||||
import useSWR from 'swr'
|
||||
import Navbar from './navbar'
|
||||
import Footer from './footer'
|
||||
|
||||
export default function Layout({ children }) {
|
||||
const { data, error } = useSWR('/api/navigation', fetcher)
|
||||
|
||||
if (error) return <div>Failed to load</div>
|
||||
if (!data) return <div>Loading...</div>
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar links={data.links} />
|
||||
<main>{children}</main>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
Generated
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: Dynamic Routes
|
||||
description: Dynamic Routes are pages that allow you to add custom params to your URLs. Start creating Dynamic Routes and learn more here.
|
||||
related:
|
||||
title: Next Steps
|
||||
description: For more information on what to do next, we recommend the following sections
|
||||
links:
|
||||
- pages/building-your-application/routing/linking-and-navigating
|
||||
- pages/api-reference/functions/use-router
|
||||
---
|
||||
|
||||
When you don't know the exact segment names ahead of time and want to create routes from dynamic data, you can use Dynamic Segments that are filled in at request time or [prerendered](/docs/pages/building-your-application/data-fetching/get-static-paths) at build time.
|
||||
|
||||
## Convention
|
||||
|
||||
A Dynamic Segment can be created by wrapping a file or folder name in square brackets: `[segmentName]`. For example, `[id]` or `[slug]`.
|
||||
|
||||
Dynamic Segments can be accessed from [`useRouter`](/docs/pages/api-reference/functions/use-router).
|
||||
|
||||
## Example
|
||||
|
||||
For example, a blog could include the following route `pages/blog/[slug].js` where `[slug]` is the Dynamic Segment for blog posts.
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Page() {
|
||||
const router = useRouter()
|
||||
return <p>Post: {router.query.slug}</p>
|
||||
}
|
||||
```
|
||||
|
||||
| Route | Example URL | `params` |
|
||||
| ---------------------- | ----------- | --------------- |
|
||||
| `pages/blog/[slug].js` | `/blog/a` | `{ slug: 'a' }` |
|
||||
| `pages/blog/[slug].js` | `/blog/b` | `{ slug: 'b' }` |
|
||||
| `pages/blog/[slug].js` | `/blog/c` | `{ slug: 'c' }` |
|
||||
|
||||
## Catch-all Segments
|
||||
|
||||
Dynamic Segments can be extended to **catch-all** subsequent segments by adding an ellipsis inside the brackets `[...segmentName]`.
|
||||
|
||||
For example, `pages/shop/[...slug].js` will match `/shop/clothes`, but also `/shop/clothes/tops`, `/shop/clothes/tops/t-shirts`, and so on.
|
||||
|
||||
| Route | Example URL | `params` |
|
||||
| ------------------------- | ------------- | --------------------------- |
|
||||
| `pages/shop/[...slug].js` | `/shop/a` | `{ slug: ['a'] }` |
|
||||
| `pages/shop/[...slug].js` | `/shop/a/b` | `{ slug: ['a', 'b'] }` |
|
||||
| `pages/shop/[...slug].js` | `/shop/a/b/c` | `{ slug: ['a', 'b', 'c'] }` |
|
||||
|
||||
## Optional Catch-all Segments
|
||||
|
||||
Catch-all Segments can be made **optional** by including the parameter in double square brackets: `[[...segmentName]]`.
|
||||
|
||||
For example, `pages/shop/[[...slug]].js` will **also** match `/shop`, in addition to `/shop/clothes`, `/shop/clothes/tops`, `/shop/clothes/tops/t-shirts`.
|
||||
|
||||
The difference between **catch-all** and **optional catch-all** segments is that with optional, the route without the parameter is also matched (`/shop` in the example above).
|
||||
|
||||
| Route | Example URL | `params` |
|
||||
| --------------------------- | ------------- | --------------------------- |
|
||||
| `pages/shop/[[...slug]].js` | `/shop` | `{ slug: undefined }` |
|
||||
| `pages/shop/[[...slug]].js` | `/shop/a` | `{ slug: ['a'] }` |
|
||||
| `pages/shop/[[...slug]].js` | `/shop/a/b` | `{ slug: ['a', 'b'] }` |
|
||||
| `pages/shop/[[...slug]].js` | `/shop/a/b/c` | `{ slug: ['a', 'b', 'c'] }` |
|
||||
Generated
Vendored
+184
@@ -0,0 +1,184 @@
|
||||
---
|
||||
title: Linking and Navigating
|
||||
description: Learn how navigation works in Next.js, and how to use the Link Component and `useRouter` hook.
|
||||
---
|
||||
|
||||
The Next.js router allows you to do client-side route transitions between pages, similar to a single-page application.
|
||||
|
||||
A React component called `Link` is provided to do this client-side route transition.
|
||||
|
||||
```jsx
|
||||
import Link from 'next/link'
|
||||
|
||||
function Home() {
|
||||
return (
|
||||
<ul>
|
||||
<li>
|
||||
<Link href="/">Home</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/about">About Us</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/blog/hello-world">Blog Post</Link>
|
||||
</li>
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
||||
```
|
||||
|
||||
The example above uses multiple links. Each one maps a path (`href`) to a known page:
|
||||
|
||||
- `/` → `pages/index.js`
|
||||
- `/about` → `pages/about.js`
|
||||
- `/blog/hello-world` → `pages/blog/[slug].js`
|
||||
|
||||
Any `<Link />` in the viewport (initially or through scroll) will be prefetched by default (including the corresponding data) for pages using [Static Generation](/docs/pages/building-your-application/data-fetching/get-static-props). The corresponding data for [server-rendered](/docs/pages/building-your-application/data-fetching/get-server-side-props) routes is fetched _only when_ the `<Link />` is clicked.
|
||||
|
||||
## Linking to dynamic paths
|
||||
|
||||
You can also use interpolation to create the path, which comes in handy for [dynamic route segments](/docs/pages/building-your-application/routing/dynamic-routes). For example, to show a list of posts which have been passed to the component as a prop:
|
||||
|
||||
```jsx
|
||||
import Link from 'next/link'
|
||||
|
||||
function Posts({ posts }) {
|
||||
return (
|
||||
<ul>
|
||||
{posts.map((post) => (
|
||||
<li key={post.id}>
|
||||
<Link href={`/blog/${encodeURIComponent(post.slug)}`}>
|
||||
{post.title}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
export default Posts
|
||||
```
|
||||
|
||||
> [`encodeURIComponent`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) is used in the example to keep the path utf-8 compatible.
|
||||
|
||||
Alternatively, using a URL Object:
|
||||
|
||||
```jsx
|
||||
import Link from 'next/link'
|
||||
|
||||
function Posts({ posts }) {
|
||||
return (
|
||||
<ul>
|
||||
{posts.map((post) => (
|
||||
<li key={post.id}>
|
||||
<Link
|
||||
href={{
|
||||
pathname: '/blog/[slug]',
|
||||
query: { slug: post.slug },
|
||||
}}
|
||||
>
|
||||
{post.title}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
export default Posts
|
||||
```
|
||||
|
||||
Now, instead of using interpolation to create the path, we use a URL object in `href` where:
|
||||
|
||||
- `pathname` is the name of the page in the `pages` directory. `/blog/[slug]` in this case.
|
||||
- `query` is an object with the dynamic segment. `slug` in this case.
|
||||
|
||||
## Injecting the router
|
||||
|
||||
To access the [`router` object](/docs/pages/api-reference/functions/use-router#router-object) in a React component you can use [`useRouter`](/docs/pages/api-reference/functions/use-router) or [`withRouter`](/docs/pages/api-reference/functions/use-router#withrouter).
|
||||
|
||||
In general we recommend using [`useRouter`](/docs/pages/api-reference/functions/use-router).
|
||||
|
||||
## Imperative Routing
|
||||
|
||||
[`next/link`](/docs/pages/api-reference/components/link) should be able to cover most of your routing needs, but you can also do client-side navigations without it, take a look at the [documentation for `next/router`](/docs/pages/api-reference/functions/use-router).
|
||||
|
||||
The following example shows how to do basic page navigations with [`useRouter`](/docs/pages/api-reference/functions/use-router):
|
||||
|
||||
```jsx
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function ReadMore() {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<button onClick={() => router.push('/about')}>
|
||||
Click here to read more
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Shallow Routing
|
||||
|
||||
<details>
|
||||
<summary>Examples</summary>
|
||||
|
||||
- [Shallow Routing](https://github.com/vercel/next.js/tree/canary/examples/with-shallow-routing)
|
||||
|
||||
</details>
|
||||
|
||||
Shallow routing allows you to change the URL without running data fetching methods again, that includes [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props), [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props), and [`getInitialProps`](/docs/pages/api-reference/functions/get-initial-props).
|
||||
|
||||
You'll receive the updated `pathname` and the `query` via the [`router` object](/docs/pages/api-reference/functions/use-router#router-object) (added by [`useRouter`](/docs/pages/api-reference/functions/use-router) or [`withRouter`](/docs/pages/api-reference/functions/use-router#withrouter)), without losing state.
|
||||
|
||||
To enable shallow routing, set the `shallow` option to `true`. Consider the following example:
|
||||
|
||||
```jsx
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
// Current URL is '/'
|
||||
function Page() {
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
// Always do navigations after the first render
|
||||
router.push('/?counter=10', undefined, { shallow: true })
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// The counter changed!
|
||||
}, [router.query.counter])
|
||||
}
|
||||
|
||||
export default Page
|
||||
```
|
||||
|
||||
The URL will get updated to `/?counter=10` and the page won't get replaced, only the state of the route is changed.
|
||||
|
||||
You can also watch for URL changes via [`componentDidUpdate`](https://react.dev/reference/react/Component#componentdidupdate) as shown below:
|
||||
|
||||
```jsx
|
||||
componentDidUpdate(prevProps) {
|
||||
const { pathname, query } = this.props.router
|
||||
// verify props have changed to avoid an infinite loop
|
||||
if (query.counter !== prevProps.router.query.counter) {
|
||||
// fetch data based on the new query
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Caveats
|
||||
|
||||
Shallow routing **only** works for URL changes in the current page. For example, let's assume we have another page called `pages/about.js`, and you run this:
|
||||
|
||||
```js
|
||||
router.push('/?counter=10', '/about?counter=10', { shallow: true })
|
||||
```
|
||||
|
||||
Since that's a new page, it'll unload the current page, load the new one and wait for data fetching even though we asked to do shallow routing.
|
||||
|
||||
When shallow routing is used with proxy it will not ensure the new page matches the current page like previously done without proxy. This is due to proxy being able to rewrite dynamically and can't be verified client-side without a data fetch which is skipped with shallow, so a shallow route change must always be treated as shallow.
|
||||
Generated
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
---
|
||||
title: Custom App
|
||||
description: Control page initialization and add a layout that persists for all pages by overriding the default App component used by Next.js.
|
||||
---
|
||||
|
||||
Next.js uses the `App` component to initialize pages. You can override it and control the page initialization and:
|
||||
|
||||
- Create a shared layout between page changes
|
||||
- Inject additional data into pages
|
||||
- [Add global CSS](/docs/app/getting-started/css)
|
||||
|
||||
## Usage
|
||||
|
||||
To override the default `App`, create the file `pages/_app` as shown below:
|
||||
|
||||
```tsx filename="pages/_app.tsx" switcher
|
||||
import type { AppProps } from 'next/app'
|
||||
|
||||
export default function MyApp({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/_app.jsx" switcher
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
```
|
||||
|
||||
The `Component` prop is the active `page`, so whenever you navigate between routes, `Component` will change to the new `page`. Therefore, any props you send to `Component` will be received by the `page`.
|
||||
|
||||
`pageProps` is an object with the initial props that were preloaded for your page by one of our [data fetching methods](/docs/pages/building-your-application/data-fetching), otherwise it's an empty object.
|
||||
|
||||
> **Good to know**:
|
||||
>
|
||||
> - If your app is running and you added a custom `App`, you'll need to restart the development server. Only required if `pages/_app.js` didn't exist before.
|
||||
> - `App` does not support Next.js [Data Fetching methods](/docs/pages/building-your-application/data-fetching) like [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) or [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props).
|
||||
|
||||
## `getInitialProps` with `App`
|
||||
|
||||
Using [`getInitialProps`](/docs/pages/api-reference/functions/get-initial-props) in `App` will disable [Automatic Static Optimization](/docs/pages/building-your-application/rendering/automatic-static-optimization) for pages without [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props).
|
||||
|
||||
**We do not recommend using this pattern.** Instead, consider [incrementally adopting](/docs/app/guides/migrating/app-router-migration) the App Router, which allows you to more easily fetch data for pages and layouts.
|
||||
|
||||
```tsx filename="pages/_app.tsx" switcher
|
||||
import App, { AppContext, AppInitialProps, AppProps } from 'next/app'
|
||||
|
||||
type AppOwnProps = { example: string }
|
||||
|
||||
export default function MyApp({
|
||||
Component,
|
||||
pageProps,
|
||||
example,
|
||||
}: AppProps & AppOwnProps) {
|
||||
return (
|
||||
<>
|
||||
<p>Data: {example}</p>
|
||||
<Component {...pageProps} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
MyApp.getInitialProps = async (
|
||||
context: AppContext
|
||||
): Promise<AppOwnProps & AppInitialProps> => {
|
||||
const ctx = await App.getInitialProps(context)
|
||||
|
||||
return { ...ctx, example: 'data' }
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/_app.jsx" switcher
|
||||
import App from 'next/app'
|
||||
|
||||
export default function MyApp({ Component, pageProps, example }) {
|
||||
return (
|
||||
<>
|
||||
<p>Data: {example}</p>
|
||||
<Component {...pageProps} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
MyApp.getInitialProps = async (context) => {
|
||||
const ctx = await App.getInitialProps(context)
|
||||
|
||||
return { ...ctx, example: 'data' }
|
||||
}
|
||||
```
|
||||
Generated
Vendored
+147
@@ -0,0 +1,147 @@
|
||||
---
|
||||
title: Custom Document
|
||||
description: Extend the default document markup added by Next.js.
|
||||
---
|
||||
|
||||
A custom `Document` can update the `<html>` and `<body>` tags used to render a [Page](/docs/pages/building-your-application/routing/pages-and-layouts).
|
||||
|
||||
To override the default `Document`, create the file `pages/_document` as shown below:
|
||||
|
||||
```tsx filename="pages/_document.tsx" switcher
|
||||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/_document.jsx" switcher
|
||||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**:
|
||||
>
|
||||
> - `_document` is only rendered on the server, so event handlers like `onClick` cannot be used in this file.
|
||||
> - `<Html>`, `<Head />`, `<Main />` and `<NextScript />` are required for the page to be properly rendered.
|
||||
|
||||
## Caveats
|
||||
|
||||
- The `<Head />` component used in `_document` is not the same as [`next/head`](/docs/pages/api-reference/components/head). The `<Head />` component used here should only be used for any `<head>` code that is common for all pages. For all other cases, such as `<title>` tags, we recommend using [`next/head`](/docs/pages/api-reference/components/head) in your pages or components.
|
||||
- React components outside of `<Main />` will not be initialized by the browser. Do _not_ add application logic here or custom CSS (like `styled-jsx`). If you need shared components in all your pages (like a menu or a toolbar), read [Layouts](/docs/pages/building-your-application/routing/pages-and-layouts#layout-pattern) instead.
|
||||
- `Document` currently does not support Next.js [Data Fetching methods](/docs/pages/building-your-application/data-fetching) like [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) or [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props).
|
||||
|
||||
## Customizing `renderPage`
|
||||
|
||||
Customizing `renderPage` is advanced and only needed for libraries like CSS-in-JS to support server-side rendering. This is not needed for built-in `styled-jsx` support.
|
||||
|
||||
**We do not recommend using this pattern.** Instead, consider [incrementally adopting](/docs/app/guides/migrating/app-router-migration) the App Router, which allows you to more easily fetch data for pages and layouts.
|
||||
|
||||
```tsx filename="pages/_document.tsx" switcher
|
||||
import Document, {
|
||||
Html,
|
||||
Head,
|
||||
Main,
|
||||
NextScript,
|
||||
DocumentContext,
|
||||
DocumentInitialProps,
|
||||
} from 'next/document'
|
||||
|
||||
class MyDocument extends Document {
|
||||
static async getInitialProps(
|
||||
ctx: DocumentContext
|
||||
): Promise<DocumentInitialProps> {
|
||||
const originalRenderPage = ctx.renderPage
|
||||
|
||||
// Run the React rendering logic synchronously
|
||||
ctx.renderPage = () =>
|
||||
originalRenderPage({
|
||||
// Useful for wrapping the whole react tree
|
||||
enhanceApp: (App) => App,
|
||||
// Useful for wrapping in a per-page basis
|
||||
enhanceComponent: (Component) => Component,
|
||||
})
|
||||
|
||||
// Run the parent `getInitialProps`, it now includes the custom `renderPage`
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
|
||||
return initialProps
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyDocument
|
||||
```
|
||||
|
||||
```jsx filename="pages/_document.jsx" switcher
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
class MyDocument extends Document {
|
||||
static async getInitialProps(ctx) {
|
||||
const originalRenderPage = ctx.renderPage
|
||||
|
||||
// Run the React rendering logic synchronously
|
||||
ctx.renderPage = () =>
|
||||
originalRenderPage({
|
||||
// Useful for wrapping the whole react tree
|
||||
enhanceApp: (App) => App,
|
||||
// Useful for wrapping in a per-page basis
|
||||
enhanceComponent: (Component) => Component,
|
||||
})
|
||||
|
||||
// Run the parent `getInitialProps`, it now includes the custom `renderPage`
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
|
||||
return initialProps
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyDocument
|
||||
```
|
||||
|
||||
> **Good to know**:
|
||||
>
|
||||
> - `getInitialProps` in `_document` is not called during client-side transitions.
|
||||
> - The `ctx` object for `_document` is equivalent to the one received in [`getInitialProps`](/docs/pages/api-reference/functions/get-initial-props#context-object), with the addition of `renderPage`.
|
||||
Generated
Vendored
+459
@@ -0,0 +1,459 @@
|
||||
---
|
||||
title: API Routes
|
||||
description: Next.js supports API Routes, which allow you to build your API without leaving your Next.js app. Learn how it works here.
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary>Examples</summary>
|
||||
|
||||
- [API Routes Request Helpers](https://github.com/vercel/next.js/tree/canary/examples/api-routes-proxy)
|
||||
- [API Routes with GraphQL](https://github.com/vercel/next.js/tree/canary/examples/api-routes-graphql)
|
||||
- [API Routes with REST](https://github.com/vercel/next.js/tree/canary/examples/api-routes-rest)
|
||||
- [API Routes with CORS](https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors)
|
||||
|
||||
</details>
|
||||
|
||||
> **Good to know**: If you are using the App Router, you can use [Server Components](/docs/app/getting-started/server-and-client-components) or [Route Handlers](/docs/app/api-reference/file-conventions/route) instead of API Routes.
|
||||
|
||||
API routes provide a solution to build a **public API** with Next.js.
|
||||
|
||||
Any file inside the folder `pages/api` is mapped to `/api/*` and will be treated as an API endpoint instead of a `page`. They are server-side only bundles and won't increase your client-side bundle size.
|
||||
|
||||
For example, the following API route returns a JSON response with a status code of `200`:
|
||||
|
||||
```ts filename="pages/api/hello.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
type ResponseData = {
|
||||
message: string
|
||||
}
|
||||
|
||||
export default function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<ResponseData>
|
||||
) {
|
||||
res.status(200).json({ message: 'Hello from Next.js!' })
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/hello.js" switcher
|
||||
export default function handler(req, res) {
|
||||
res.status(200).json({ message: 'Hello from Next.js!' })
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**:
|
||||
>
|
||||
> - API Routes [do not specify CORS headers](https://developer.mozilla.org/docs/Web/HTTP/CORS), meaning they are **same-origin only** by default. You can customize such behavior by wrapping the request handler with the [CORS request helpers](https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors).
|
||||
> - API Routes can't be used with [static exports](/docs/pages/guides/static-exports). However, [Route Handlers](/docs/app/api-reference/file-conventions/route) in the App Router can.
|
||||
> - API Routes will be affected by [`pageExtensions` configuration](/docs/pages/api-reference/config/next-config-js/pageExtensions) in `next.config.js`.
|
||||
|
||||
## Parameters
|
||||
|
||||
```tsx
|
||||
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
- `req`: An instance of [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)
|
||||
- `res`: An instance of [http.ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse)
|
||||
|
||||
## HTTP Methods
|
||||
|
||||
To handle different HTTP methods in an API route, you can use `req.method` in your request handler, like so:
|
||||
|
||||
```ts filename="pages/api/hello.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method === 'POST') {
|
||||
// Process a POST request
|
||||
} else {
|
||||
// Handle any other HTTP method
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/hello.js" switcher
|
||||
export default function handler(req, res) {
|
||||
if (req.method === 'POST') {
|
||||
// Process a POST request
|
||||
} else {
|
||||
// Handle any other HTTP method
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Request Helpers
|
||||
|
||||
API Routes provide built-in request helpers which parse the incoming request (`req`):
|
||||
|
||||
- `req.cookies` - An object containing the cookies sent by the request. Defaults to `{}`
|
||||
- `req.query` - An object containing the [query string](https://en.wikipedia.org/wiki/Query_string). Defaults to `{}`
|
||||
- `req.body` - An object containing the body parsed by `content-type`, or `null` if no body was sent
|
||||
|
||||
### Custom config
|
||||
|
||||
Every API Route can export a `config` object to change the default configuration, which is the following:
|
||||
|
||||
```js
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: {
|
||||
sizeLimit: '1mb',
|
||||
},
|
||||
},
|
||||
// Specifies the maximum allowed duration for this function to execute (in seconds)
|
||||
maxDuration: 5,
|
||||
}
|
||||
```
|
||||
|
||||
`bodyParser` is automatically enabled. If you want to consume the body as a `Stream` or with [`raw-body`](https://www.npmjs.com/package/raw-body), you can set this to `false`.
|
||||
|
||||
One use case for disabling the automatic `bodyParsing` is to allow you to verify the raw body of a **webhook** request, for example [from GitHub](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks#validating-payloads-from-github).
|
||||
|
||||
```js
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
`bodyParser.sizeLimit` is the maximum size allowed for the parsed body, in any format supported by [bytes](https://github.com/visionmedia/bytes.js), like so:
|
||||
|
||||
```js
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: {
|
||||
sizeLimit: '500kb',
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
`externalResolver` is an explicit flag that tells the server that this route is being handled by an external resolver like _express_ or _connect_. Enabling this option disables warnings for unresolved requests.
|
||||
|
||||
```js
|
||||
export const config = {
|
||||
api: {
|
||||
externalResolver: true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
`responseLimit` is automatically enabled, warning when an API Routes' response body is over 4MB.
|
||||
|
||||
If you are not using Next.js in a serverless environment, and understand the performance implications of not using a CDN or dedicated media host, you can set this limit to `false`.
|
||||
|
||||
```js
|
||||
export const config = {
|
||||
api: {
|
||||
responseLimit: false,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
`responseLimit` can also take the number of bytes or any string format supported by `bytes`, for example `1000`, `'500kb'` or `'3mb'`.
|
||||
This value will be the maximum response size before a warning is displayed. Default is 4MB. (see above)
|
||||
|
||||
```js
|
||||
export const config = {
|
||||
api: {
|
||||
responseLimit: '8mb',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Response Helpers
|
||||
|
||||
The [Server Response object](https://nodejs.org/api/http.html#http_class_http_serverresponse), (often abbreviated as `res`) includes a set of Express.js-like helper methods to improve the developer experience and increase the speed of creating new API endpoints.
|
||||
|
||||
The included helpers are:
|
||||
|
||||
- `res.status(code)` - A function to set the status code. `code` must be a valid [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
|
||||
- `res.json(body)` - Sends a JSON response. `body` must be a [serializable object](https://developer.mozilla.org/docs/Glossary/Serialization)
|
||||
- `res.send(body)` - Sends the HTTP response. `body` can be a `string`, an `object` or a `Buffer`
|
||||
- `res.redirect([status,] path)` - Redirects to a specified path or URL. `status` must be a valid [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes). If not specified, `status` defaults to "307" "Temporary redirect".
|
||||
- `res.revalidate(urlPath)` - [Revalidate a page on demand](/docs/pages/guides/incremental-static-regeneration#on-demand-revalidation-with-revalidatepath) using `getStaticProps`. `urlPath` must be a `string`.
|
||||
|
||||
### Setting the status code of a response
|
||||
|
||||
When sending a response back to the client, you can set the status code of the response.
|
||||
|
||||
The following example sets the status code of the response to `200` (`OK`) and returns a `message` property with the value of `Hello from Next.js!` as a JSON response:
|
||||
|
||||
```ts filename="pages/api/hello.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
type ResponseData = {
|
||||
message: string
|
||||
}
|
||||
|
||||
export default function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<ResponseData>
|
||||
) {
|
||||
res.status(200).json({ message: 'Hello from Next.js!' })
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/hello.js" switcher
|
||||
export default function handler(req, res) {
|
||||
res.status(200).json({ message: 'Hello from Next.js!' })
|
||||
}
|
||||
```
|
||||
|
||||
### Sending a JSON response
|
||||
|
||||
When sending a response back to the client you can send a JSON response, this must be a [serializable object](https://developer.mozilla.org/docs/Glossary/Serialization).
|
||||
In a real world application you might want to let the client know the status of the request depending on the result of the requested endpoint.
|
||||
|
||||
The following example sends a JSON response with the status code `200` (`OK`) and the result of the async operation. It's contained in a try catch block to handle any errors that may occur, with the appropriate status code and error message caught and sent back to the client:
|
||||
|
||||
```ts filename="pages/api/hello.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
try {
|
||||
const result = await someAsyncOperation()
|
||||
res.status(200).json({ result })
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'failed to load data' })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/hello.js" switcher
|
||||
export default async function handler(req, res) {
|
||||
try {
|
||||
const result = await someAsyncOperation()
|
||||
res.status(200).json({ result })
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'failed to load data' })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Sending a HTTP response
|
||||
|
||||
Sending an HTTP response works the same way as when sending a JSON response. The only difference is that the response body can be a `string`, an `object` or a `Buffer`.
|
||||
|
||||
The following example sends a HTTP response with the status code `200` (`OK`) and the result of the async operation.
|
||||
|
||||
```ts filename="pages/api/hello.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
try {
|
||||
const result = await someAsyncOperation()
|
||||
res.status(200).send({ result })
|
||||
} catch (err) {
|
||||
res.status(500).send({ error: 'failed to fetch data' })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/hello.js" switcher
|
||||
export default async function handler(req, res) {
|
||||
try {
|
||||
const result = await someAsyncOperation()
|
||||
res.status(200).send({ result })
|
||||
} catch (err) {
|
||||
res.status(500).send({ error: 'failed to fetch data' })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Redirects to a specified path or URL
|
||||
|
||||
Taking a form as an example, you may want to redirect your client to a specified path or URL once they have submitted the form.
|
||||
|
||||
The following example redirects the client to the `/` path if the form is successfully submitted:
|
||||
|
||||
```ts filename="pages/api/hello.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const { name, message } = req.body
|
||||
|
||||
try {
|
||||
await handleFormInputAsync({ name, message })
|
||||
res.redirect(307, '/')
|
||||
} catch (err) {
|
||||
res.status(500).send({ error: 'Failed to fetch data' })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/hello.js" switcher
|
||||
export default async function handler(req, res) {
|
||||
const { name, message } = req.body
|
||||
|
||||
try {
|
||||
await handleFormInputAsync({ name, message })
|
||||
res.redirect(307, '/')
|
||||
} catch (err) {
|
||||
res.status(500).send({ error: 'failed to fetch data' })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Adding TypeScript types
|
||||
|
||||
You can make your API Routes more type-safe by importing the `NextApiRequest` and `NextApiResponse` types from `next`, in addition to those, you can also type your response data:
|
||||
|
||||
```ts
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
type ResponseData = {
|
||||
message: string
|
||||
}
|
||||
|
||||
export default function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<ResponseData>
|
||||
) {
|
||||
res.status(200).json({ message: 'Hello from Next.js!' })
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**: The body of `NextApiRequest` is `any` because the client may include any payload. You should validate the type/shape of the body at runtime before using it.
|
||||
|
||||
## Dynamic API Routes
|
||||
|
||||
API Routes support [dynamic routes](/docs/pages/building-your-application/routing/dynamic-routes), and follow the same file naming rules used for `pages/`.
|
||||
|
||||
```ts filename="pages/api/post/[pid].ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { pid } = req.query
|
||||
res.end(`Post: ${pid}`)
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/post/[pid].js" switcher
|
||||
export default function handler(req, res) {
|
||||
const { pid } = req.query
|
||||
res.end(`Post: ${pid}`)
|
||||
}
|
||||
```
|
||||
|
||||
Now, a request to `/api/post/abc` will respond with the text: `Post: abc`.
|
||||
|
||||
### Catch all API routes
|
||||
|
||||
API Routes can be extended to catch all paths by adding three dots (`...`) inside the brackets. For example:
|
||||
|
||||
- `pages/api/post/[...slug].js` matches `/api/post/a`, but also `/api/post/a/b`, `/api/post/a/b/c` and so on.
|
||||
|
||||
> **Good to know**: You can use names other than `slug`, such as: `[...param]`
|
||||
|
||||
Matched parameters will be sent as a query parameter (`slug` in the example) to the page, and it will always be an array, so, the path `/api/post/a` will have the following `query` object:
|
||||
|
||||
```json
|
||||
{ "slug": ["a"] }
|
||||
```
|
||||
|
||||
And in the case of `/api/post/a/b`, and any other matching path, new parameters will be added to the array, like so:
|
||||
|
||||
```json
|
||||
{ "slug": ["a", "b"] }
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```ts filename="pages/api/post/[...slug].ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const { slug } = req.query
|
||||
res.end(`Post: ${slug.join(', ')}`)
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/post/[...slug].js" switcher
|
||||
export default function handler(req, res) {
|
||||
const { slug } = req.query
|
||||
res.end(`Post: ${slug.join(', ')}`)
|
||||
}
|
||||
```
|
||||
|
||||
Now, a request to `/api/post/a/b/c` will respond with the text: `Post: a, b, c`.
|
||||
|
||||
### Optional catch all API routes
|
||||
|
||||
Catch all routes can be made optional by including the parameter in double brackets (`[[...slug]]`).
|
||||
|
||||
For example, `pages/api/post/[[...slug]].js` will match `/api/post`, `/api/post/a`, `/api/post/a/b`, and so on.
|
||||
|
||||
The main difference between catch all and optional catch all routes is that with optional, the route without the parameter is also matched (`/api/post` in the example above).
|
||||
|
||||
The `query` objects are as follows:
|
||||
|
||||
```json
|
||||
{ } // GET `/api/post` (empty object)
|
||||
{ "slug": ["a"] } // `GET /api/post/a` (single-element array)
|
||||
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (multi-element array)
|
||||
```
|
||||
|
||||
### Caveats
|
||||
|
||||
- Predefined API routes take precedence over dynamic API routes, and dynamic API routes over catch all API routes. Take a look at the following examples:
|
||||
- `pages/api/post/create.js` - Will match `/api/post/create`
|
||||
- `pages/api/post/[pid].js` - Will match `/api/post/1`, `/api/post/abc`, etc. But not `/api/post/create`
|
||||
- `pages/api/post/[...slug].js` - Will match `/api/post/1/2`, `/api/post/a/b/c`, etc. But not `/api/post/create`, `/api/post/abc`
|
||||
|
||||
## Streaming responses
|
||||
|
||||
While the Pages Router does support streaming responses with API Routes, we recommend incrementally adopting the App Router and using [Route Handlers](/docs/app/api-reference/file-conventions/route) if you are on Next.js 14+.
|
||||
|
||||
Here's how you can stream a response from an API Route with `writeHead`:
|
||||
|
||||
```ts filename="pages/api/hello.ts" switcher
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-store',
|
||||
})
|
||||
let i = 0
|
||||
while (i < 10) {
|
||||
res.write(`data: ${i}\n\n`)
|
||||
i++
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
}
|
||||
res.end()
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/hello.js" switcher
|
||||
export default async function handler(req, res) {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-store',
|
||||
})
|
||||
let i = 0
|
||||
while (i < 10) {
|
||||
res.write(`data: ${i}\n\n`)
|
||||
i++
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
}
|
||||
res.end()
|
||||
}
|
||||
```
|
||||
Generated
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
---
|
||||
title: Custom Errors
|
||||
description: Override and extend the built-in Error page to handle custom errors.
|
||||
---
|
||||
|
||||
## 404 Page
|
||||
|
||||
A 404 page may be accessed very often. Server-rendering an error page for every visit increases the load of the Next.js server. This can result in increased costs and slow experiences.
|
||||
|
||||
To avoid the above pitfalls, Next.js provides a static 404 page by default without having to add any additional files.
|
||||
|
||||
### Customizing The 404 Page
|
||||
|
||||
To create a custom 404 page you can create a `pages/404.js` file. This file is statically generated at build time.
|
||||
|
||||
```jsx filename="pages/404.js"
|
||||
export default function Custom404() {
|
||||
return <h1>404 - Page Not Found</h1>
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**: You can use [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) inside this page if you need to fetch data at build time.
|
||||
|
||||
## 500 Page
|
||||
|
||||
Server-rendering an error page for every visit adds complexity to responding to errors. To help users get responses to errors as fast as possible, Next.js provides a static 500 page by default without having to add any additional files.
|
||||
|
||||
### Customizing The 500 Page
|
||||
|
||||
To customize the 500 page you can create a `pages/500.js` file. This file is statically generated at build time.
|
||||
|
||||
```jsx filename="pages/500.js"
|
||||
export default function Custom500() {
|
||||
return <h1>500 - Server-side error occurred</h1>
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**: You can use [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) inside this page if you need to fetch data at build time.
|
||||
|
||||
### More Advanced Error Page Customizing
|
||||
|
||||
500 errors are handled both client-side and server-side by the `Error` component. If you wish to override it, define the file `pages/_error.js` and add the following code:
|
||||
|
||||
```jsx
|
||||
function Error({ statusCode }) {
|
||||
return (
|
||||
<p>
|
||||
{statusCode
|
||||
? `An error ${statusCode} occurred on server`
|
||||
: 'An error occurred on client'}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
Error.getInitialProps = ({ res, err }) => {
|
||||
const statusCode = res ? res.statusCode : err ? err.statusCode : 404
|
||||
return { statusCode }
|
||||
}
|
||||
|
||||
export default Error
|
||||
```
|
||||
|
||||
> `pages/_error.js` is only used in production. In development you’ll get an error with the call stack to know where the error originated from.
|
||||
|
||||
### Reusing the built-in error page
|
||||
|
||||
If you want to render the built-in error page you can by importing the `Error` component:
|
||||
|
||||
```jsx
|
||||
import Error from 'next/error'
|
||||
|
||||
export async function getServerSideProps() {
|
||||
const res = await fetch('https://api.github.com/repos/vercel/next.js')
|
||||
const errorCode = res.ok ? false : res.status
|
||||
const json = await res.json()
|
||||
|
||||
return {
|
||||
props: { errorCode, stars: json.stargazers_count },
|
||||
}
|
||||
}
|
||||
|
||||
export default function Page({ errorCode, stars }) {
|
||||
if (errorCode) {
|
||||
return <Error statusCode={errorCode} />
|
||||
}
|
||||
|
||||
return <div>Next stars: {stars}</div>
|
||||
}
|
||||
```
|
||||
|
||||
The `Error` component also takes `title` as a property if you want to pass in a text message along with a `statusCode`.
|
||||
|
||||
If you have a custom `Error` component be sure to import that one instead. `next/error` exports the default component used by Next.js.
|
||||
|
||||
### Caveats
|
||||
|
||||
- `Error` does not currently support Next.js [Data Fetching methods](/docs/pages/building-your-application/data-fetching) like [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) or [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props).
|
||||
- `_error`, like `_app`, is a reserved pathname. `_error` is used to define the customized layouts and behaviors of the error pages. `/_error` will render 404 when accessed directly via [routing](/docs/pages/building-your-application/routing) or rendering in a [custom server](/docs/pages/guides/custom-server).
|
||||
Generated
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Routing
|
||||
description: Learn the fundamentals of routing for front-end applications with the Pages Router.
|
||||
---
|
||||
|
||||
The Pages Router has a file-system based router built on concepts of pages. When a file is added to the `pages` directory it's automatically available as a route. Learn more about routing in the Pages Router:
|
||||
Generated
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
---
|
||||
title: Server-side Rendering (SSR)
|
||||
description: Use Server-side Rendering to render pages on each request.
|
||||
---
|
||||
|
||||
> Also referred to as "SSR" or "Dynamic Rendering".
|
||||
|
||||
If a page uses **Server-side Rendering**, the page HTML is generated on **each request**.
|
||||
|
||||
To use Server-side Rendering for a page, you need to `export` an `async` function called `getServerSideProps`. This function will be called by the server on every request.
|
||||
|
||||
For example, suppose that your page needs to prerender frequently updated data (fetched from an external API). You can write `getServerSideProps` which fetches this data and passes it to `Page` like below:
|
||||
|
||||
```jsx
|
||||
export default function Page({ data }) {
|
||||
// Render data...
|
||||
}
|
||||
|
||||
// This gets called on every request
|
||||
export async function getServerSideProps() {
|
||||
// Fetch data from external API
|
||||
const res = await fetch(`https://.../data`)
|
||||
const data = await res.json()
|
||||
|
||||
// Pass data to the page via props
|
||||
return { props: { data } }
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, `getServerSideProps` is similar to `getStaticProps`, but the difference is that `getServerSideProps` is run on every request instead of on build time.
|
||||
|
||||
To learn more about how `getServerSideProps` works, check out our [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/get-server-side-props).
|
||||
Generated
Vendored
+183
@@ -0,0 +1,183 @@
|
||||
---
|
||||
title: Static Site Generation (SSG)
|
||||
description: Use Static Site Generation (SSG) to prerender pages at build time.
|
||||
---
|
||||
|
||||
<details>
|
||||
<summary>Examples</summary>
|
||||
|
||||
- [Agility CMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-agilitycms) ([Demo](https://next-blog-agilitycms.vercel.app/))
|
||||
- [Builder.io Example](https://github.com/vercel/next.js/tree/canary/examples/cms-builder-io) ([Demo](https://cms-builder-io.vercel.app/))
|
||||
- [ButterCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-buttercms) ([Demo](https://next-blog-buttercms.vercel.app/))
|
||||
- [Contentful Example](https://github.com/vercel/next.js/tree/canary/examples/cms-contentful) ([Demo](https://app-router-contentful.vercel.app/))
|
||||
- [Cosmic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-cosmic) ([Demo](https://next-blog-cosmic.vercel.app/))
|
||||
- [DatoCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-datocms) ([Demo](https://next-blog-datocms.vercel.app/))
|
||||
- [DotCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-dotcms) ([Demo](https://nextjs-dotcms-blog.vercel.app/))
|
||||
- [Drupal Example](https://github.com/vercel/next.js/tree/canary/examples/cms-drupal) ([Demo](https://cms-drupal.vercel.app/))
|
||||
- [Enterspeed Example](https://github.com/vercel/next.js/tree/canary/examples/cms-enterspeed) ([Demo](https://next-blog-demo.enterspeed.com/))
|
||||
- [GraphCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-graphcms) ([Demo](https://next-blog-graphcms.vercel.app/))
|
||||
- [Keystone Example](https://github.com/vercel/next.js/tree/canary/examples/cms-keystonejs-embedded) ([Demo](https://nextjs-keystone-demo.vercel.app/))
|
||||
- [Kontent.ai Example](https://github.com/vercel/next.js/tree/canary/examples/cms-kontent-ai) ([Demo](https://next-blog-kontent-ai.vercel.app/))
|
||||
- [Makeswift Example](https://github.com/vercel/next.js/tree/canary/examples/cms-makeswift) ([Demo](https://nextjs-makeswift-example.vercel.app/))
|
||||
- [Plasmic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-plasmic) ([Demo](https://nextjs-plasmic-example.vercel.app/))
|
||||
- [Prepr Example](https://github.com/vercel/next.js/tree/canary/examples/cms-prepr) ([Demo](https://next-blog-prepr.vercel.app/))
|
||||
- [Prismic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-prismic) ([Demo](https://next-blog-prismic.vercel.app/))
|
||||
- [Sanity Example](https://github.com/vercel/next.js/tree/canary/examples/cms-sanity) ([Demo](https://next-blog.sanity.build/))
|
||||
- [Sitecore XM Cloud Example](https://github.com/vercel/next.js/tree/canary/examples/cms-sitecore-xmcloud) ([Demo](https://vercel-sitecore-xmcloud-demo.vercel.app/))
|
||||
- [Storyblok Example](https://github.com/vercel/next.js/tree/canary/examples/cms-storyblok) ([Demo](https://next-blog-storyblok.vercel.app/))
|
||||
- [Strapi Example](https://github.com/vercel/next.js/tree/canary/examples/cms-strapi) ([Demo](https://next-blog-strapi.vercel.app/))
|
||||
- [TakeShape Example](https://github.com/vercel/next.js/tree/canary/examples/cms-takeshape) ([Demo](https://next-blog-takeshape.vercel.app/))
|
||||
- [Tina Example](https://github.com/vercel/next.js/tree/canary/examples/cms-tina) ([Demo](https://cms-tina-example.vercel.app/))
|
||||
- [Umbraco Example](https://github.com/vercel/next.js/tree/canary/examples/cms-umbraco) ([Demo](https://nextjs-umbraco-sample-blog.vercel.app/))
|
||||
- [Umbraco Heartcore Example](https://github.com/vercel/next.js/tree/canary/examples/cms-umbraco-heartcore) ([Demo](https://next-blog-umbraco-heartcore.vercel.app/))
|
||||
- [Webiny Example](https://github.com/vercel/next.js/tree/canary/examples/cms-webiny) ([Demo](https://webiny-headlesscms-nextjs-example.vercel.app/))
|
||||
- [WordPress Example](https://github.com/vercel/next.js/tree/canary/examples/cms-wordpress) ([Demo](https://next-blog-wordpress.vercel.app/))
|
||||
- [Blog Starter Example](https://github.com/vercel/next.js/tree/canary/examples/blog-starter) ([Demo](https://next-blog-starter.vercel.app/))
|
||||
- [Static Tweet (Demo)](https://react-tweet.vercel.app/)
|
||||
|
||||
</details>
|
||||
|
||||
If a page uses **Static Generation**, the page HTML is generated at **build time**. That means in production, the page HTML is generated when you run `next build`. This HTML will then be reused on each request. It can be cached by a CDN.
|
||||
|
||||
In Next.js, you can statically generate pages **with or without data**. Let's take a look at each case.
|
||||
|
||||
### Static Generation without data
|
||||
|
||||
By default, Next.js prerenders pages using Static Generation without fetching data. Here's an example:
|
||||
|
||||
```jsx
|
||||
function About() {
|
||||
return <div>About</div>
|
||||
}
|
||||
|
||||
export default About
|
||||
```
|
||||
|
||||
Note that this page does not need to fetch any external data to be prerendered. In cases like this, Next.js generates a single HTML file per page during build time.
|
||||
|
||||
### Static Generation with data
|
||||
|
||||
Some pages require fetching external data for prerendering. There are two scenarios, and one or both might apply. In each case, you can use these functions that Next.js provides:
|
||||
|
||||
1. Your page **content** depends on external data: Use `getStaticProps`.
|
||||
2. Your page **paths** depend on external data: Use `getStaticPaths` (usually in addition to `getStaticProps`).
|
||||
|
||||
#### Scenario 1: Your page content depends on external data
|
||||
|
||||
**Example**: Your blog page might need to fetch the list of blog posts from a CMS (content management system).
|
||||
|
||||
```jsx
|
||||
// TODO: Need to fetch `posts` (by calling some API endpoint)
|
||||
// before this page can be prerendered.
|
||||
export default function Blog({ posts }) {
|
||||
return (
|
||||
<ul>
|
||||
{posts.map((post) => (
|
||||
<li>{post.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
To fetch this data on prerender, Next.js allows you to `export` an `async` function called `getStaticProps` from the same file. This function gets called at build time and lets you pass fetched data to the page's `props` on prerender.
|
||||
|
||||
```jsx
|
||||
export default function Blog({ posts }) {
|
||||
// Render posts...
|
||||
}
|
||||
|
||||
// This function gets called at build time
|
||||
export async function getStaticProps() {
|
||||
// Call an external API endpoint to get posts
|
||||
const res = await fetch('https://.../posts')
|
||||
const posts = await res.json()
|
||||
|
||||
// By returning { props: { posts } }, the Blog component
|
||||
// will receive `posts` as a prop at build time
|
||||
return {
|
||||
props: {
|
||||
posts,
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To learn more about how `getStaticProps` works, check out the [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/get-static-props).
|
||||
|
||||
#### Scenario 2: Your page paths depend on external data
|
||||
|
||||
Next.js allows you to create pages with **dynamic routes**. For example, you can create a file called `pages/posts/[id].js` to show a single blog post based on `id`. This will allow you to show a blog post with `id: 1` when you access `posts/1`.
|
||||
|
||||
> To learn more about dynamic routing, check the [Dynamic Routing documentation](/docs/pages/building-your-application/routing/dynamic-routes).
|
||||
|
||||
However, which `id` you want to prerender at build time might depend on external data.
|
||||
|
||||
**Example**: suppose that you've only added one blog post (with `id: 1`) to the database. In this case, you'd only want to prerender `posts/1` at build time.
|
||||
|
||||
Later, you might add the second post with `id: 2`. Then you'd want to prerender `posts/2` as well.
|
||||
|
||||
So your page **paths** that are prerendered depend on external data. To handle this, Next.js lets you `export` an `async` function called `getStaticPaths` from a dynamic page (`pages/posts/[id].js` in this case). This function gets called at build time and lets you specify which paths you want to prerender.
|
||||
|
||||
```jsx
|
||||
// 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 }
|
||||
}
|
||||
```
|
||||
|
||||
Also in `pages/posts/[id].js`, you need to export `getStaticProps` so that you can fetch the data about the post with this `id` and use it to prerender the page:
|
||||
|
||||
```jsx
|
||||
export default function Post({ post }) {
|
||||
// Render post...
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
// ...
|
||||
}
|
||||
|
||||
// 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 } }
|
||||
}
|
||||
```
|
||||
|
||||
To learn more about how `getStaticPaths` works, check out the [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/get-static-paths).
|
||||
|
||||
### When should I use Static Generation?
|
||||
|
||||
We recommend using **Static Generation** (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request.
|
||||
|
||||
You can use Static Generation for many types of pages, including:
|
||||
|
||||
- Marketing pages
|
||||
- Blog posts and portfolios
|
||||
- E-commerce product listings
|
||||
- Help and documentation
|
||||
|
||||
You should ask yourself: "Can I prerender this page **ahead** of a user's request?" If the answer is yes, then you should choose Static Generation.
|
||||
|
||||
On the other hand, Static Generation is **not** a good idea if you cannot prerender a page ahead of a user's request. Maybe your page shows frequently updated data, and the page content changes on every request.
|
||||
|
||||
In cases like this, you can do one of the following:
|
||||
|
||||
- Use Static Generation with **Client-side data fetching:** You can skip prerendering some parts of a page and then use client-side JavaScript to populate them. To learn more about this approach, check out the [Data Fetching documentation](/docs/pages/building-your-application/data-fetching/client-side).
|
||||
- Use **Server-Side Rendering:** Next.js prerenders a page on each request. It will be slower because the page cannot be cached by a CDN, but the prerendered page will always be up-to-date. We'll talk about this approach below.
|
||||
Generated
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: Automatic Static Optimization
|
||||
description: Next.js automatically optimizes your app to be static HTML whenever possible. Learn how it works here.
|
||||
---
|
||||
|
||||
Next.js automatically determines that a page is static (can be prerendered) if it has no blocking data requirements. This determination is made by the absence of `getServerSideProps` and `getInitialProps` in the page.
|
||||
|
||||
This feature allows Next.js to emit hybrid applications that contain **both server-rendered and statically generated pages**.
|
||||
|
||||
> **Good to know**: Statically generated pages are still reactive. Next.js will hydrate your application client-side to give it full interactivity.
|
||||
|
||||
One of the main benefits of this feature is that optimized pages require no server-side computation, and can be instantly streamed to the end-user from multiple CDN locations. The result is an _ultra fast_ loading experience for your users.
|
||||
|
||||
## How it works
|
||||
|
||||
If `getServerSideProps` or `getInitialProps` is present in a page, Next.js will switch to render the page on-demand, per-request (meaning [Server-Side Rendering](/docs/pages/building-your-application/rendering/server-side-rendering)).
|
||||
|
||||
If the above is not the case, Next.js will **statically optimize** your page automatically by prerendering the page to static HTML.
|
||||
|
||||
During prerendering, the router's `query` object will be empty since we do not have `query` information to provide during this phase. After hydration, Next.js will trigger an update to your application to provide the route parameters in the `query` object.
|
||||
|
||||
The cases where the query will be updated after hydration triggering another render are:
|
||||
|
||||
- The page is a [dynamic-route](/docs/pages/building-your-application/routing/dynamic-routes).
|
||||
- The page has query values in the URL.
|
||||
- [Rewrites](/docs/pages/api-reference/config/next-config-js/rewrites) are configured in your `next.config.js` since these can have parameters that may need to be parsed and provided in the `query`.
|
||||
|
||||
To be able to distinguish if the query is fully updated and ready for use, you can leverage the `isReady` field on [`next/router`](/docs/pages/api-reference/functions/use-router#router-object).
|
||||
|
||||
> **Good to know**: Parameters added with [dynamic routes](/docs/pages/building-your-application/routing/dynamic-routes) to a page that's using [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) will always be available inside the `query` object.
|
||||
|
||||
`next build` will emit `.html` files for statically optimized pages. For example, the result for the page `pages/about.js` would be:
|
||||
|
||||
```bash filename="Terminal"
|
||||
.next/server/pages/about.html
|
||||
```
|
||||
|
||||
And if you add `getServerSideProps` to the page, it will then be JavaScript, like so:
|
||||
|
||||
```bash filename="Terminal"
|
||||
.next/server/pages/about.js
|
||||
```
|
||||
|
||||
## Caveats
|
||||
|
||||
- If you have a [custom `App`](/docs/pages/building-your-application/routing/custom-app) with `getInitialProps` then this optimization will be turned off in pages without [Static Generation](/docs/pages/building-your-application/data-fetching/get-static-props).
|
||||
- If you have a [custom `Document`](/docs/pages/building-your-application/routing/custom-document) with `getInitialProps` be sure you check if `ctx.req` is defined before assuming the page is server-side rendered. `ctx.req` will be `undefined` for pages that are prerendered.
|
||||
- Avoid using the `asPath` value on [`next/router`](/docs/pages/api-reference/functions/use-router#router-object) in the rendering tree until the router's `isReady` field is `true`. Statically optimized pages only know `asPath` on the client and not the server, so using it as a prop may lead to mismatch errors. The [`active-class-name` example](https://github.com/vercel/next.js/tree/canary/examples/active-class-name) demonstrates one way to use `asPath` as a prop.
|
||||
Generated
Vendored
+71
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: Client-side Rendering (CSR)
|
||||
description: Learn how to implement client-side rendering in the Pages Router.
|
||||
related:
|
||||
description: Learn about the alternative rendering methods in Next.js.
|
||||
links:
|
||||
- pages/building-your-application/rendering/server-side-rendering
|
||||
- pages/building-your-application/rendering/static-site-generation
|
||||
- pages/guides/incremental-static-regeneration
|
||||
---
|
||||
|
||||
In Client-Side Rendering (CSR) with React, the browser downloads a minimal HTML page and the JavaScript needed for the page. The JavaScript is then used to update the DOM and render the page. When the application is first loaded, the user may notice a slight delay before they can see the full page, this is because the page isn't fully rendered until all the JavaScript is downloaded, parsed, and executed.
|
||||
|
||||
After the page has been loaded for the first time, navigating to other pages on the same website is typically faster, as only necessary data needs to be fetched, and JavaScript can re-render parts of the page without requiring a full page refresh.
|
||||
|
||||
In Next.js, there are two ways you can implement client-side rendering:
|
||||
|
||||
1. Using React's `useEffect()` hook inside your pages instead of the server-side rendering methods ([`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) and [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props)).
|
||||
2. Using a data fetching library like [SWR](https://swr.vercel.app/) or [TanStack Query](https://tanstack.com/query/latest/) to fetch data on the client (recommended).
|
||||
|
||||
Here's an example of using `useEffect()` inside a Next.js page:
|
||||
|
||||
```jsx filename="pages/index.js"
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
export function Page() {
|
||||
const [data, setData] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const response = await fetch('https://api.example.com/data')
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
}
|
||||
const result = await response.json()
|
||||
setData(result)
|
||||
}
|
||||
|
||||
fetchData().catch((e) => {
|
||||
// handle the error as needed
|
||||
console.error('An error occurred while fetching the data: ', e)
|
||||
})
|
||||
}, [])
|
||||
|
||||
return <p>{data ? `Your data: ${data}` : 'Loading...'}</p>
|
||||
}
|
||||
```
|
||||
|
||||
In the example above, the component starts by rendering `Loading...`. Then, once the data is fetched, it re-renders and displays the data.
|
||||
|
||||
Although fetching data in a `useEffect` is a pattern you may see in older React Applications, we recommend using a data-fetching library for better performance, caching, optimistic updates, and more. Here's a minimum example using [SWR](https://swr.vercel.app/) to fetch data on the client:
|
||||
|
||||
```jsx filename="pages/index.js"
|
||||
import useSWR from 'swr'
|
||||
|
||||
export function Page() {
|
||||
const { data, error, isLoading } = useSWR(
|
||||
'https://api.example.com/data',
|
||||
fetcher
|
||||
)
|
||||
|
||||
if (error) return <p>Failed to load.</p>
|
||||
if (isLoading) return <p>Loading...</p>
|
||||
|
||||
return <p>Your Data: {data}</p>
|
||||
}
|
||||
```
|
||||
|
||||
> **Good to know**:
|
||||
>
|
||||
> Keep in mind that CSR can impact SEO. Some search engine crawlers might not execute JavaScript and therefore only see the initial empty or loading state of your application. It can also lead to performance issues for users with slower internet connections or devices, as they need to wait for all the JavaScript to load and run before they can see the full page. Next.js promotes a hybrid approach that allows you to use a combination of [server-side rendering](/docs/pages/building-your-application/rendering/server-side-rendering), [static site generation](/docs/pages/building-your-application/rendering/static-site-generation), and client-side rendering, **depending on the needs of each page** in your application. In the App Router, you can also use [Loading UI with Suspense](/docs/app/api-reference/file-conventions/loading) to show a loading indicator while the page is being rendered.
|
||||
Generated
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Rendering
|
||||
description: Learn the fundamentals of rendering in React and Next.js.
|
||||
---
|
||||
|
||||
By default, Next.js **prerenders** every page. This means that Next.js generates HTML for each page in advance, instead of having it all done by client-side JavaScript. Prerendering can result in better performance and SEO.
|
||||
|
||||
Each generated HTML is associated with minimal JavaScript code necessary for that page. When a page is loaded by the browser, its JavaScript code runs and makes the page fully interactive (this process is called [hydration](https://react.dev/reference/react-dom/client/hydrateRoot) in React).
|
||||
|
||||
### Prerendering
|
||||
|
||||
Next.js has two forms of prerendering: **Static Generation** and **Server-side Rendering**. The difference is in **when** it generates the HTML for a page.
|
||||
|
||||
- Static Generation: The HTML is generated at **build time** and will be reused on each request.
|
||||
- Server-side Rendering: The HTML is generated on **each request**.
|
||||
|
||||
Importantly, Next.js lets you choose which prerendering form you'd like to use for each page. You can create a "hybrid" Next.js app by using Static Generation for most pages and using Server-side Rendering for others.
|
||||
|
||||
We recommend using Static Generation over Server-side Rendering for performance reasons. Statically generated pages can be cached by CDN with no extra configuration to boost performance. However, in some cases, Server-side Rendering might be the only option.
|
||||
|
||||
You can also use client-side data fetching along with Static Generation or Server-side Rendering. That means some parts of a page can be rendered entirely by clientside JavaScript. To learn more, take a look at the [Data Fetching](/docs/pages/building-your-application/data-fetching/client-side) documentation.
|
||||
Generated
Vendored
+202
@@ -0,0 +1,202 @@
|
||||
---
|
||||
title: getStaticProps
|
||||
description: Fetch data and generate static pages with `getStaticProps`. Learn more about this API for data fetching in Next.js.
|
||||
---
|
||||
|
||||
If you export a function called `getStaticProps` (Static Site Generation) from a page, Next.js will prerender this page at build time using the props returned by `getStaticProps`.
|
||||
|
||||
```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
|
||||
}
|
||||
```
|
||||
|
||||
> Note that irrespective of rendering type, any `props` will be passed to the page component and can be viewed 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`.
|
||||
|
||||
The [`getStaticProps` API reference](/docs/pages/api-reference/functions/get-static-props) covers all parameters and props that can be used with `getStaticProps`.
|
||||
|
||||
## When should I use getStaticProps?
|
||||
|
||||
You should use `getStaticProps` if:
|
||||
|
||||
- The data required to render the page is available at build time ahead of a user’s request
|
||||
- The data comes from a headless CMS
|
||||
- The page must be prerendered (for SEO) and be very fast — `getStaticProps` generates `HTML` and `JSON` files, both of which can be cached by a CDN for performance
|
||||
- The data can be publicly cached (not user-specific). This condition can be bypassed in certain specific situation by using a Proxy to rewrite the path.
|
||||
|
||||
## When does getStaticProps run
|
||||
|
||||
`getStaticProps` always runs on the server and never on the client. You can validate code written inside `getStaticProps` is removed from the client-side bundle [with this tool](https://next-code-elimination.vercel.app/).
|
||||
|
||||
- `getStaticProps` always runs during `next build`
|
||||
- `getStaticProps` runs in the background when using [`fallback: true`](/docs/pages/api-reference/functions/get-static-paths#fallback-true)
|
||||
- `getStaticProps` is called before initial render when using [`fallback: blocking`](/docs/pages/api-reference/functions/get-static-paths#fallback-blocking)
|
||||
- `getStaticProps` runs in the background when using `revalidate`
|
||||
- `getStaticProps` runs on-demand in the background when using [`revalidate()`](/docs/pages/guides/incremental-static-regeneration#on-demand-revalidation-with-revalidatepath)
|
||||
|
||||
When combined with [Incremental Static Regeneration](/docs/pages/guides/incremental-static-regeneration), `getStaticProps` will run in the background while the stale page is being revalidated, and the fresh page served to the browser.
|
||||
|
||||
`getStaticProps` does not have access to the incoming request (such as query parameters or HTTP headers) as it generates static HTML. If you need access to the request for your page, consider using [Proxy](/docs/pages/api-reference/file-conventions/proxy) in addition to `getStaticProps`.
|
||||
|
||||
## Using getStaticProps to fetch data from a CMS
|
||||
|
||||
The following example shows how you can fetch a list of blog posts from a CMS.
|
||||
|
||||
```tsx filename="pages/blog.tsx" switcher
|
||||
// posts will be populated at build time by getStaticProps()
|
||||
export default function Blog({ posts }) {
|
||||
return (
|
||||
<ul>
|
||||
{posts.map((post) => (
|
||||
<li>{post.title}</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() {
|
||||
// Call an external API endpoint to get posts.
|
||||
// You can use any data fetching library
|
||||
const res = await fetch('https://.../posts')
|
||||
const posts = await res.json()
|
||||
|
||||
// By returning { props: { posts } }, the Blog component
|
||||
// will receive `posts` as a prop at build time
|
||||
return {
|
||||
props: {
|
||||
posts,
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/blog.js" switcher
|
||||
// posts will be populated at build time by getStaticProps()
|
||||
export default function Blog({ posts }) {
|
||||
return (
|
||||
<ul>
|
||||
{posts.map((post) => (
|
||||
<li>{post.title}</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() {
|
||||
// Call an external API endpoint to get posts.
|
||||
// You can use any data fetching library
|
||||
const res = await fetch('https://.../posts')
|
||||
const posts = await res.json()
|
||||
|
||||
// By returning { props: { posts } }, the Blog component
|
||||
// will receive `posts` as a prop at build time
|
||||
return {
|
||||
props: {
|
||||
posts,
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The [`getStaticProps` API reference](/docs/pages/api-reference/functions/get-static-props) covers all parameters and props that can be used with `getStaticProps`.
|
||||
|
||||
## Write server-side code directly
|
||||
|
||||
As `getStaticProps` runs only on the server-side, it will never run on the client-side. It won’t even be included in the JS bundle for the browser, so you can write direct database queries without them being sent to browsers.
|
||||
|
||||
This means that instead of fetching an **API route** from `getStaticProps` (that itself fetches data from an external source), you can write the server-side code directly in `getStaticProps`.
|
||||
|
||||
Take the following example. An API route is used to fetch some data from a CMS. That API route is then called directly from `getStaticProps`. This produces an additional call, reducing performance. Instead, the logic for fetching the data from the CMS can be shared by using a `lib/` directory. Then it can be shared with `getStaticProps`.
|
||||
|
||||
```js filename="lib/load-posts.js"
|
||||
// The following function is shared
|
||||
// with getStaticProps and API routes
|
||||
// from a `lib/` directory
|
||||
export async function loadPosts() {
|
||||
// Call an external API endpoint to get posts
|
||||
const res = await fetch('https://.../posts/')
|
||||
const data = await res.json()
|
||||
|
||||
return data
|
||||
}
|
||||
```
|
||||
|
||||
```jsx filename="pages/blog.js"
|
||||
// pages/blog.js
|
||||
import { loadPosts } from '../lib/load-posts'
|
||||
|
||||
// This function runs only on the server side
|
||||
export async function getStaticProps() {
|
||||
// Instead of fetching your `/api` route you can call the same
|
||||
// function directly in `getStaticProps`
|
||||
const posts = await loadPosts()
|
||||
|
||||
// Props returned will be passed to the page component
|
||||
return { props: { posts } }
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, if you are **not** using API routes to fetch data, then the [`fetch()`](https://developer.mozilla.org/docs/Web/API/Fetch_API) API _can_ be used directly in `getStaticProps` to fetch data.
|
||||
|
||||
To verify what Next.js eliminates from the client-side bundle, you can use the [next-code-elimination tool](https://next-code-elimination.vercel.app/).
|
||||
|
||||
## Statically generates both HTML and JSON
|
||||
|
||||
When a page with `getStaticProps` is prerendered at build time, in addition to the page HTML file, Next.js generates a JSON file holding the result of running `getStaticProps`.
|
||||
|
||||
This JSON file will be used in client-side routing through [`next/link`](/docs/pages/api-reference/components/link) or [`next/router`](/docs/pages/api-reference/functions/use-router). When you navigate to a page that’s prerendered using `getStaticProps`, Next.js fetches this JSON file (pre-computed at build time) and uses it as the props for the page component. This means that client-side page transitions will **not** call `getStaticProps` as only the exported JSON is used.
|
||||
|
||||
When using Incremental Static Generation, `getStaticProps` will be executed in the background to generate the JSON needed for client-side navigation. You may see this in the form of multiple requests being made for the same page, however, this is intended and has no impact on end-user performance.
|
||||
|
||||
## Where can I use getStaticProps
|
||||
|
||||
`getStaticProps` can only be exported from a **page**. You **cannot** export it from non-page files, `_app`, `_document`, or `_error`.
|
||||
|
||||
One of the reasons for this restriction is that React needs to have all the required data before the page is rendered.
|
||||
|
||||
Also, you must use export `getStaticProps` as a standalone function — it will **not** work if you add `getStaticProps` as a property of the page component.
|
||||
|
||||
> **Good to know**: if you have created a [custom app](/docs/pages/building-your-application/routing/custom-app), ensure you are passing the `pageProps` to the page component as shown in the linked document, otherwise the props will be empty.
|
||||
|
||||
## Runs on every request in development
|
||||
|
||||
In development (`next dev`), `getStaticProps` will be called on every request.
|
||||
|
||||
## Preview Mode
|
||||
|
||||
You can temporarily bypass static generation and render the page at **request time** instead of build time using [**Preview Mode**](/docs/pages/guides/preview-mode). For example, you might be using a headless CMS and want to preview drafts before they're published.
|
||||
Generated
Vendored
+141
@@ -0,0 +1,141 @@
|
||||
---
|
||||
title: getStaticPaths
|
||||
description: Fetch data and generate static pages with `getStaticPaths`. Learn more about this API for data fetching in Next.js.
|
||||
---
|
||||
|
||||
If a page has [Dynamic Routes](/docs/pages/building-your-application/routing/dynamic-routes) and uses `getStaticProps`, it needs to define a list of paths to be statically generated.
|
||||
|
||||
When you export a function called `getStaticPaths` (Static Site Generation) from a page that uses 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
|
||||
}
|
||||
```
|
||||
|
||||
The [`getStaticPaths` API reference](/docs/pages/api-reference/functions/get-static-paths) covers all parameters and props that can be used with `getStaticPaths`.
|
||||
|
||||
## When should I use getStaticPaths?
|
||||
|
||||
You should use `getStaticPaths` if you’re statically prerendering pages that use dynamic routes and:
|
||||
|
||||
- The data comes from a headless CMS
|
||||
- The data comes from a database
|
||||
- The data comes from the filesystem
|
||||
- The data can be publicly cached (not user-specific)
|
||||
- The page must be prerendered (for SEO) and be very fast — `getStaticProps` generates `HTML` and `JSON` files, both of which can be cached by a CDN for performance
|
||||
|
||||
## When does getStaticPaths run
|
||||
|
||||
`getStaticPaths` will only run during build in production, it will not be called during runtime. You can validate code written inside `getStaticPaths` is removed from the client-side bundle [with this tool](https://next-code-elimination.vercel.app/).
|
||||
|
||||
### How does getStaticProps run with regards to getStaticPaths
|
||||
|
||||
- `getStaticProps` runs during `next build` for any `paths` returned during build
|
||||
- `getStaticProps` runs in the background when using `fallback: true`
|
||||
- `getStaticProps` is called before initial render when using `fallback: blocking`
|
||||
|
||||
## Where can I use getStaticPaths
|
||||
|
||||
- `getStaticPaths` **must** be used with `getStaticProps`
|
||||
- You **cannot** use `getStaticPaths` with [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props)
|
||||
- You can export `getStaticPaths` from a [Dynamic Route](/docs/pages/building-your-application/routing/dynamic-routes) that also uses `getStaticProps`
|
||||
- You **cannot** export `getStaticPaths` from non-page file (e.g. your `components` folder)
|
||||
- You must export `getStaticPaths` as a standalone function, and not a property of the page component
|
||||
|
||||
## Runs on every request in development
|
||||
|
||||
In development (`next dev`), `getStaticPaths` will be called on every request.
|
||||
|
||||
## Generating paths on-demand
|
||||
|
||||
`getStaticPaths` allows you to control which pages are generated during the build instead of on-demand with [`fallback`](/docs/pages/api-reference/functions/get-static-paths#fallback-blocking). Generating more pages during a build will cause slower builds.
|
||||
|
||||
You can defer generating all pages on-demand by returning an empty array for `paths`. This can be especially helpful when deploying your Next.js application to multiple environments. For example, you can have faster builds by generating all pages on-demand for previews (but not production builds). This is helpful for sites with hundreds/thousands of static pages.
|
||||
|
||||
```jsx filename="pages/posts/[id].js"
|
||||
export async function getStaticPaths() {
|
||||
// When this is true (in preview environments) don't
|
||||
// prerender any static pages
|
||||
// (faster builds, but slower initial page load)
|
||||
if (process.env.SKIP_BUILD_STATIC_GENERATION) {
|
||||
return {
|
||||
paths: [],
|
||||
fallback: 'blocking',
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// In production environments, prerender all pages
|
||||
// (slower builds, but faster initial page load)
|
||||
const paths = posts.map((post) => ({
|
||||
params: { id: post.id },
|
||||
}))
|
||||
|
||||
// { fallback: false } means other routes should 404
|
||||
return { paths, fallback: false }
|
||||
}
|
||||
```
|
||||
Generated
Vendored
+107
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: Forms and Mutations
|
||||
nav_title: Forms and Mutations
|
||||
description: Learn how to handle form submissions and data mutations with Next.js.
|
||||
---
|
||||
|
||||
Forms enable you to create and update data in web applications. Next.js provides a powerful way to handle form submissions and data mutations using **API Routes**.
|
||||
|
||||
> **Good to know:**
|
||||
>
|
||||
> - We will soon recommend [incrementally adopting](/docs/app/guides/migrating/app-router-migration) the App Router and using [Server Actions](/docs/app/getting-started/mutating-data) for handling form submissions and data mutations. Server Actions allow you to define asynchronous server functions that can be called directly from your components, without needing to manually create an API Route.
|
||||
> - API Routes [do not specify CORS headers](https://developer.mozilla.org/docs/Web/HTTP/CORS), meaning they are same-origin only by default.
|
||||
> - Since API Routes run on the server, we're able to use sensitive values (like API keys) through [Environment Variables](/docs/pages/guides/environment-variables) without exposing them to the client. This is critical for the security of your application.
|
||||
|
||||
## Examples
|
||||
|
||||
### Redirecting
|
||||
|
||||
If you would like to redirect the user to a different route after a mutation, you can [`redirect`](/docs/pages/building-your-application/routing/api-routes#response-helpers) to any absolute or relative URL:
|
||||
|
||||
```ts filename="pages/api/submit.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const id = await addPost()
|
||||
res.redirect(307, `/post/${id}`)
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/submit.js" switcher
|
||||
export default async function handler(req, res) {
|
||||
const id = await addPost()
|
||||
res.redirect(307, `/post/${id}`)
|
||||
}
|
||||
```
|
||||
|
||||
### Setting cookies
|
||||
|
||||
You can set cookies inside an API Route using the `setHeader` method on the response:
|
||||
|
||||
```ts filename="pages/api/cookie.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
res.setHeader('Set-Cookie', 'username=lee; Path=/; HttpOnly')
|
||||
res.status(200).send('Cookie has been set.')
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/cookie.js" switcher
|
||||
export default async function handler(req, res) {
|
||||
res.setHeader('Set-Cookie', 'username=lee; Path=/; HttpOnly')
|
||||
res.status(200).send('Cookie has been set.')
|
||||
}
|
||||
```
|
||||
|
||||
### Reading cookies
|
||||
|
||||
You can read cookies inside an API Route using the [`cookies`](/docs/pages/building-your-application/routing/api-routes#request-helpers) request helper:
|
||||
|
||||
```ts filename="pages/api/cookie.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const auth = req.cookies.authorization
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/cookie.js" switcher
|
||||
export default async function handler(req, res) {
|
||||
const auth = req.cookies.authorization
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Deleting cookies
|
||||
|
||||
You can delete cookies inside an API Route using the `setHeader` method on the response:
|
||||
|
||||
```ts filename="pages/api/cookie.ts" switcher
|
||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
res.setHeader('Set-Cookie', 'username=; Path=/; HttpOnly; Max-Age=0')
|
||||
res.status(200).send('Cookie has been deleted.')
|
||||
}
|
||||
```
|
||||
|
||||
```js filename="pages/api/cookie.js" switcher
|
||||
export default async function handler(req, res) {
|
||||
res.setHeader('Set-Cookie', 'username=; Path=/; HttpOnly; Max-Age=0')
|
||||
res.status(200).send('Cookie has been deleted.')
|
||||
}
|
||||
```
|
||||
Generated
Vendored
+108
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: getServerSideProps
|
||||
description: Fetch data on each request with `getServerSideProps`.
|
||||
---
|
||||
|
||||
`getServerSideProps` is a Next.js function that can be used to fetch data and render the contents of a page at request time.
|
||||
|
||||
## Example
|
||||
|
||||
You can use `getServerSideProps` by exporting it from a Page Component. The example below shows how you can fetch data from a 3rd party API in `getServerSideProps`, and pass the data to the page as props:
|
||||
|
||||
```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>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## When should I use `getServerSideProps`?
|
||||
|
||||
You should use `getServerSideProps` if you need to render a page that relies on personalized user data, or information that can only be known at request time. For example, `authorization` headers or a geolocation.
|
||||
|
||||
If you do not need to fetch the data at request time, or would prefer to cache the data and prerendered HTML, we recommend using [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props).
|
||||
|
||||
## Behavior
|
||||
|
||||
- `getServerSideProps` runs on the server.
|
||||
- `getServerSideProps` can only be exported from a **page**.
|
||||
- `getServerSideProps` returns JSON.
|
||||
- When a user visits a page, `getServerSideProps` will be used to fetch data at request time, and the data is used to render the initial HTML of the page.
|
||||
- `props` passed to the page component can be viewed on the client as part of 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`.
|
||||
- When a user visits the page through [`next/link`](/docs/pages/api-reference/components/link) or [`next/router`](/docs/pages/api-reference/functions/use-router), Next.js sends an API request to the server, which runs `getServerSideProps`.
|
||||
- You do not have to call a Next.js [API Route](/docs/pages/building-your-application/routing/api-routes) to fetch data when using `getServerSideProps` since the function runs on the server. Instead, you can call a CMS, database, or other third-party APIs directly from inside `getServerSideProps`.
|
||||
|
||||
> **Good to know:**
|
||||
>
|
||||
> - See [`getServerSideProps` API reference](/docs/pages/api-reference/functions/get-server-side-props) for parameters and props that can be used with `getServerSideProps`.
|
||||
> - You can use the [next-code-elimination tool](https://next-code-elimination.vercel.app/) to verify what Next.js eliminates from the client-side bundle.
|
||||
|
||||
## Error Handling
|
||||
|
||||
If an error is thrown inside `getServerSideProps`, it will show the `pages/500.js` file. Check out the documentation for [500 page](/docs/pages/building-your-application/routing/custom-error#500-page) to learn more on how to create it. During development, this file will not be used and the development error overlay will be shown instead.
|
||||
|
||||
## Edge Cases
|
||||
|
||||
### Caching with Server-Side Rendering (SSR)
|
||||
|
||||
You can use caching headers (`Cache-Control`) inside `getServerSideProps` to cache dynamic responses. For example, using [`stale-while-revalidate`](https://web.dev/stale-while-revalidate/).
|
||||
|
||||
```jsx
|
||||
// This value is considered fresh for ten seconds (s-maxage=10).
|
||||
// If a request is repeated within the next 10 seconds, the previously
|
||||
// cached value will still be fresh. If the request is repeated before 59 seconds,
|
||||
// the cached value will be stale but still render (stale-while-revalidate=59).
|
||||
//
|
||||
// In the background, a revalidation request will be made to populate the cache
|
||||
// with a fresh value. If you refresh the page, you will see the new value.
|
||||
export async function getServerSideProps({ req, res }) {
|
||||
res.setHeader(
|
||||
'Cache-Control',
|
||||
'public, s-maxage=10, stale-while-revalidate=59'
|
||||
)
|
||||
|
||||
return {
|
||||
props: {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
However, before reaching for `cache-control`, we recommend seeing if [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) with [ISR](/docs/pages/guides/incremental-static-regeneration) is a better fit for your use case.
|
||||
node_modules/next/dist/docs/02-pages/03-building-your-application/03-data-fetching/05-client-side.md
Generated
Vendored
+70
@@ -0,0 +1,70 @@
|
||||
---
|
||||
title: Client-side Fetching
|
||||
description: Learn about client-side data fetching, and how to use SWR, a data fetching React Hook library that handles caching, revalidation, focus tracking, refetching on interval and more.
|
||||
---
|
||||
|
||||
Client-side data fetching is useful when your page doesn't require SEO indexing, when you don't need to prerender your data, or when the content of your pages needs to update frequently. Unlike the server-side rendering APIs, you can use client-side data fetching at the component level.
|
||||
|
||||
If done at the page level, the data is fetched at runtime, and the content of the page is updated as the data changes. When used at the component level, the data is fetched at the time of the component mount, and the content of the component is updated as the data changes.
|
||||
|
||||
It's important to note that using client-side data fetching can affect the performance of your application and the load speed of your pages. This is because the data fetching is done at the time of the component or pages mount, and the data is not cached.
|
||||
|
||||
## Client-side data fetching with useEffect
|
||||
|
||||
The following example shows how you can fetch data on the client side using the useEffect hook.
|
||||
|
||||
```jsx
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
function Profile() {
|
||||
const [data, setData] = useState(null)
|
||||
const [isLoading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/profile-data')
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
setData(data)
|
||||
setLoading(false)
|
||||
})
|
||||
}, [])
|
||||
|
||||
if (isLoading) return <p>Loading...</p>
|
||||
if (!data) return <p>No profile data</p>
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{data.name}</h1>
|
||||
<p>{data.bio}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Client-side data fetching with SWR
|
||||
|
||||
The team behind Next.js has created a React Hook library for data fetching called [**SWR**](https://swr.vercel.app/). It is **highly recommended** if you are fetching data on the client-side. It handles caching, revalidation, focus tracking, refetching on intervals, and more.
|
||||
|
||||
Using the same example as above, we can now use SWR to fetch the profile data. SWR will automatically cache the data for us and will revalidate the data if it becomes stale.
|
||||
|
||||
For more information on using SWR, check out the [SWR docs](https://swr.vercel.app/docs/getting-started).
|
||||
|
||||
```jsx
|
||||
import useSWR from 'swr'
|
||||
|
||||
const fetcher = (...args) => fetch(...args).then((res) => res.json())
|
||||
|
||||
function Profile() {
|
||||
const { data, error } = useSWR('/api/profile-data', fetcher)
|
||||
|
||||
if (error) return <div>Failed to load</div>
|
||||
if (!data) return <div>Loading...</div>
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>{data.name}</h1>
|
||||
<p>{data.bio}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
Generated
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
---
|
||||
title: Data Fetching
|
||||
description: Next.js allows you to fetch data in multiple ways, with prerendering, server-side rendering or static-site generation, and incremental static regeneration. Learn how to manage your application data in Next.js.
|
||||
---
|
||||
|
||||
Data fetching in Next.js allows you to render your content in different ways, depending on your application's use case. These include prerendering with **Server-side Rendering** or **Static Generation**, and updating or creating content at runtime with **Incremental Static Regeneration**.
|
||||
|
||||
## Examples
|
||||
|
||||
- [Agility CMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-agilitycms) ([Demo](https://next-blog-agilitycms.vercel.app/))
|
||||
- [Builder.io Example](https://github.com/vercel/next.js/tree/canary/examples/cms-builder-io) ([Demo](https://cms-builder-io.vercel.app/))
|
||||
- [ButterCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-buttercms) ([Demo](https://next-blog-buttercms.vercel.app/))
|
||||
- [Contentful Example](https://github.com/vercel/next.js/tree/canary/examples/cms-contentful) ([Demo](https://app-router-contentful.vercel.app/))
|
||||
- [Cosmic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-cosmic) ([Demo](https://next-blog-cosmic.vercel.app/))
|
||||
- [DatoCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-datocms) ([Demo](https://next-blog-datocms.vercel.app/))
|
||||
- [DotCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-dotcms) ([Demo](https://nextjs-dotcms-blog.vercel.app/))
|
||||
- [Drupal Example](https://github.com/vercel/next.js/tree/canary/examples/cms-drupal) ([Demo](https://cms-drupal.vercel.app/))
|
||||
- [Enterspeed Example](https://github.com/vercel/next.js/tree/canary/examples/cms-enterspeed) ([Demo](https://next-blog-demo.enterspeed.com/))
|
||||
- [GraphCMS Example](https://github.com/vercel/next.js/tree/canary/examples/cms-graphcms) ([Demo](https://next-blog-graphcms.vercel.app/))
|
||||
- [Keystone Example](https://github.com/vercel/next.js/tree/canary/examples/cms-keystonejs-embedded) ([Demo](https://nextjs-keystone-demo.vercel.app/))
|
||||
- [Kontent.ai Example](https://github.com/vercel/next.js/tree/canary/examples/cms-kontent-ai) ([Demo](https://next-blog-kontent-ai.vercel.app/))
|
||||
- [Makeswift Example](https://github.com/vercel/next.js/tree/canary/examples/cms-makeswift) ([Demo](https://nextjs-makeswift-example.vercel.app/))
|
||||
- [Plasmic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-plasmic) ([Demo](https://nextjs-plasmic-example.vercel.app/))
|
||||
- [Prepr Example](https://github.com/vercel/next.js/tree/canary/examples/cms-prepr) ([Demo](https://next-blog-prepr.vercel.app/))
|
||||
- [Prismic Example](https://github.com/vercel/next.js/tree/canary/examples/cms-prismic) ([Demo](https://next-blog-prismic.vercel.app/))
|
||||
- [Sanity Example](https://github.com/vercel/next.js/tree/canary/examples/cms-sanity) ([Demo](https://next-blog.sanity.build/))
|
||||
- [Sitecore XM Cloud Example](https://github.com/vercel/next.js/tree/canary/examples/cms-sitecore-xmcloud) ([Demo](https://vercel-sitecore-xmcloud-demo.vercel.app/))
|
||||
- [Storyblok Example](https://github.com/vercel/next.js/tree/canary/examples/cms-storyblok) ([Demo](https://next-blog-storyblok.vercel.app/))
|
||||
- [Strapi Example](https://github.com/vercel/next.js/tree/canary/examples/cms-strapi) ([Demo](https://next-blog-strapi.vercel.app/))
|
||||
- [TakeShape Example](https://github.com/vercel/next.js/tree/canary/examples/cms-takeshape) ([Demo](https://next-blog-takeshape.vercel.app/))
|
||||
- [Tina Example](https://github.com/vercel/next.js/tree/canary/examples/cms-tina) ([Demo](https://cms-tina-example.vercel.app/))
|
||||
- [Umbraco Example](https://github.com/vercel/next.js/tree/canary/examples/cms-umbraco) ([Demo](https://nextjs-umbraco-sample-blog.vercel.app/))
|
||||
- [Umbraco Heartcore Example](https://github.com/vercel/next.js/tree/canary/examples/cms-umbraco-heartcore) ([Demo](https://next-blog-umbraco-heartcore.vercel.app/))
|
||||
- [Webiny Example](https://github.com/vercel/next.js/tree/canary/examples/cms-webiny) ([Demo](https://webiny-headlesscms-nextjs-example.vercel.app/))
|
||||
- [WordPress Example](https://github.com/vercel/next.js/tree/canary/examples/cms-wordpress) ([Demo](https://next-blog-wordpress.vercel.app/))
|
||||
- [Blog Starter Example](https://github.com/vercel/next.js/tree/canary/examples/blog-starter) ([Demo](https://next-blog-starter.vercel.app/))
|
||||
- [Static Tweet (Demo)](https://react-tweet.vercel.app/)
|
||||
Generated
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
---
|
||||
title: Error Handling
|
||||
description: Handle errors in your Next.js app.
|
||||
---
|
||||
|
||||
This documentation explains how you can handle development, server-side, and client-side errors.
|
||||
|
||||
## Handling Errors in Development
|
||||
|
||||
When there is a runtime error during the development phase of your Next.js application, you will encounter an **overlay**. It is a modal that covers the webpage. It is **only** visible when the development server runs using `next dev` via `pnpm dev`, `npm run dev`, `yarn dev`, or `bun dev` and will not be shown in production. Fixing the error will automatically dismiss the overlay.
|
||||
|
||||
Here is an example of an overlay:
|
||||
|
||||
{/* TODO UPDATE SCREENSHOT */}
|
||||

|
||||
|
||||
## Handling Server Errors
|
||||
|
||||
Next.js provides a static 500 page by default to handle server-side errors that occur in your application. You can also [customize this page](/docs/pages/building-your-application/routing/custom-error#customizing-the-500-page) by creating a `pages/500.js` file.
|
||||
|
||||
Having a 500 page in your application does not show specific errors to the app user.
|
||||
|
||||
You can also use [404 page](/docs/pages/building-your-application/routing/custom-error#404-page) to handle specific runtime error like `file not found`.
|
||||
|
||||
## Handling Client Errors
|
||||
|
||||
React [Error Boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) is a graceful way to handle a JavaScript error on the client so that the other parts of the application continue working. In addition to preventing the page from crashing, it allows you to provide a custom fallback component and even log error information.
|
||||
|
||||
To use Error Boundaries for your Next.js application, you must create a class component `ErrorBoundary` and wrap the `Component` prop in the `pages/_app.js` file. This component will be responsible to:
|
||||
|
||||
- Render a fallback UI after an error is thrown
|
||||
- Provide a way to reset the Application's state
|
||||
- Log error information
|
||||
|
||||
You can create an `ErrorBoundary` class component by extending `React.Component`. For example:
|
||||
|
||||
```jsx
|
||||
class ErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
// Define a state variable to track whether is an error or not
|
||||
this.state = { hasError: false }
|
||||
}
|
||||
static getDerivedStateFromError(error) {
|
||||
// Update state so the next render will show the fallback UI
|
||||
|
||||
return { hasError: true }
|
||||
}
|
||||
componentDidCatch(error, errorInfo) {
|
||||
// You can use your own error logging service here
|
||||
console.log({ error, errorInfo })
|
||||
}
|
||||
render() {
|
||||
// Check if the error is thrown
|
||||
if (this.state.hasError) {
|
||||
// You can render any custom fallback UI
|
||||
return (
|
||||
<div>
|
||||
<h2>Oops, there is an error!</h2>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => this.setState({ hasError: false })}
|
||||
>
|
||||
Try again?
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Return children components in case of no error
|
||||
|
||||
return this.props.children
|
||||
}
|
||||
}
|
||||
|
||||
export default ErrorBoundary
|
||||
```
|
||||
|
||||
The `ErrorBoundary` component keeps track of an `hasError` state. The value of this state variable is a boolean. When the value of `hasError` is `true`, then the `ErrorBoundary` component will render a fallback UI. Otherwise, it will render the children components.
|
||||
|
||||
After creating an `ErrorBoundary` component, import it in the `pages/_app.js` file to wrap the `Component` prop in your Next.js application.
|
||||
|
||||
```jsx
|
||||
// Import the ErrorBoundary component
|
||||
import ErrorBoundary from '../components/ErrorBoundary'
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
// Wrap the Component prop with ErrorBoundary component
|
||||
<ErrorBoundary>
|
||||
<Component {...pageProps} />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
```
|
||||
|
||||
You can learn more about [Error Boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) in React's documentation.
|
||||
|
||||
### Reporting Errors
|
||||
|
||||
To monitor client errors, use a service like [Sentry](https://github.com/vercel/next.js/tree/canary/examples/with-sentry), Bugsnag or Datadog.
|
||||
Generated
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Configuring
|
||||
description: Learn how to configure your Next.js application.
|
||||
---
|
||||
|
||||
Next.js allows you to customize your project to meet specific requirements. This includes integrations with TypeScript, ESlint, and more, as well as internal configuration options such as Absolute Imports and Environment Variables.
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
---
|
||||
title: Building Your Application
|
||||
description: Learn how to use Next.js features to build your application.
|
||||
---
|
||||
Reference in New Issue
Block a user