cefdb27662
* Changes all `Note` → `Good to know` * Consistently puts the colon on the outside of bold text * Documents singe and multi-line styles in contribution guide --------- Co-authored-by: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
194 lines
9 KiB
Text
194 lines
9 KiB
Text
---
|
|
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 uses [server-centric routing](/docs/app/building-your-application/routing#server-centric-routing-with-client-side-navigation) with [client-side navigation](#how-navigation-works). It supports [instant loading states](/docs/app/building-your-application/routing/loading-ui-and-streaming) and [concurrent rendering](https://react.dev/reference/react/startTransition). This means navigation maintains client-side state, avoids expensive re-renders, is interruptible, and doesn't cause race conditions.
|
|
|
|
There are two ways to navigate between routes:
|
|
|
|
- [`<Link>` Component](#link-component)
|
|
- [`useRouter` Hook](#userouter-hook)
|
|
|
|
This page will go through how to use `<Link>`, `useRouter()`, and dive deeper into how navigation works.
|
|
|
|
## `<Link>` Component
|
|
|
|
`<Link>` is a React component that extends the HTML `<a>` element to provide [prefetching](#prefetching) and client-side navigation between routes. It is the primary way to navigate between routes in Next.js.
|
|
|
|
To use `<Link>`, import it from `next/link`, and pass a `href` prop to the component:
|
|
|
|
```tsx filename="app/page.tsx" switcher
|
|
import Link from 'next/link'
|
|
|
|
export default function Page() {
|
|
return <Link href="/dashboard">Dashboard</Link>
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/page.js" switcher
|
|
import Link from 'next/link'
|
|
|
|
export default function Page() {
|
|
return <Link href="/dashboard">Dashboard</Link>
|
|
}
|
|
```
|
|
|
|
There are optional props you can pass to `<Link>`. See the [API reference](/docs/app/api-reference/components/link) for more information.
|
|
|
|
## Examples
|
|
|
|
### Linking to Dynamic Segments
|
|
|
|
When linking to [dynamic segments](/docs/app/building-your-application/routing/dynamic-routes), you can use [template literals and interpolation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) to generate a list of links. For example, to generate a list of blog posts:
|
|
|
|
```jsx filename="app/blog/PostList.js"
|
|
import Link from 'next/link'
|
|
|
|
export default function PostList({ posts }) {
|
|
return (
|
|
<ul>
|
|
{posts.map((post) => (
|
|
<li key={post.id}>
|
|
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Checking Active Links
|
|
|
|
You can use [`usePathname()`](/docs/app/api-reference/functions/use-pathname) to determine if a link is active. For example, to add a class to the active link, you can check if the current `pathname` matches the `href` of the link:
|
|
|
|
```jsx filename="app/ui/Navigation.js"
|
|
'use client'
|
|
|
|
import { usePathname } from 'next/navigation'
|
|
import { Link } from 'next/link'
|
|
|
|
export function Navigation({ navLinks }) {
|
|
const pathname = usePathname()
|
|
|
|
return (
|
|
<>
|
|
{navLinks.map((link) => {
|
|
const isActive = pathname.startsWith(link.href)
|
|
|
|
return (
|
|
<Link
|
|
className={isActive ? 'text-blue' : 'text-black'}
|
|
href={link.href}
|
|
key={link.name}
|
|
>
|
|
{link.name}
|
|
</Link>
|
|
)
|
|
})}
|
|
</>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Scrolling to an `id`
|
|
|
|
The default behavior of `<Link>` is to [scroll to the top of the route segment that has changed](#focus-and-scroll-management). When there is an `id` defined in `href`, it will scroll to the specific `id`, similarly to a normal `<a>` tag.
|
|
|
|
To prevent scrolling to the top of the route segment, set `scroll={false}` and add a hashed `id` to `href`:
|
|
|
|
```jsx
|
|
<Link href="/#hashid" scroll={false}>
|
|
Scroll to specific id.
|
|
</Link>
|
|
```
|
|
|
|
## `useRouter()` Hook
|
|
|
|
The `useRouter` hook allows you to programmatically change routes inside [Client Components](/docs/getting-started/react-essentials).
|
|
|
|
To use `useRouter`, import it from `next/navigation`, and call the hook inside your Client Component:
|
|
|
|
```jsx filename="app/page.js"
|
|
'use client'
|
|
|
|
import { useRouter } from 'next/navigation'
|
|
|
|
export default function Page() {
|
|
const router = useRouter()
|
|
|
|
return (
|
|
<button type="button" onClick={() => router.push('/dashboard')}>
|
|
Dashboard
|
|
</button>
|
|
)
|
|
}
|
|
```
|
|
|
|
The `useRouter` provides methods such as `push()`, `refresh()`, and more. See the [API reference](/docs/app/api-reference/functions/use-router) for more information.
|
|
|
|
> **Recommendation:** Use the `<Link>` component to navigate between routes unless you have a specific requirement for using `useRouter`.
|
|
|
|
## How Navigation Works
|
|
|
|
- A route transition is initiated using `<Link>` or calling `router.push()`.
|
|
- The router updates the URL in the browser's address bar.
|
|
- The router avoids unnecessary work by re-using segments that haven't changed (e.g. shared layouts) from the [client-side cache](#client-side-caching-of-rendered-server-components). This is also referred to as [partial rendering](/docs/app/building-your-application/routing#partial-rendering).
|
|
- If the [conditions of soft navigation](#conditions-for-soft-navigation) are met, the router fetches the new segment from the cache rather than the server. If not, the router performs a [hard navigation](#hard-navigation) and fetches the Server Component payload from the server.
|
|
- If created, [loading UI](/docs/app/building-your-application/routing/loading-ui-and-streaming) is shown from the server while the payload is being fetched.
|
|
- The router uses the cached or fresh payload to render the new segments on the client.
|
|
|
|
### Client-side Caching of Rendered Server Components
|
|
|
|
> **Good to know**: This client-side cache is different from the server-side [Next.js HTTP cache](/docs/app/building-your-application/data-fetching#caching-data).
|
|
|
|
The new router has an **in-memory client-side cache** that stores the **rendered result** of Server Components (payload). The cache is split by route segments which allows invalidation at any level and ensures consistency across concurrent renders.
|
|
|
|
As users navigate around the app, the router will store the payload of previously fetched segments **and** [prefetched](#prefetching) segments in the cache.
|
|
|
|
This means, for certain cases, the router can re-use the cache instead of making a new request to the server. This improves performance by avoiding re-fetching data and re-rendering components unnecessarily.
|
|
|
|
### Invalidating the Cache
|
|
|
|
[Server Actions](/docs/app/building-your-application/data-fetching/server-actions) can be used to revalidate data on-demand by path ([`revalidatePath`](/docs/app/api-reference/functions/revalidatePath)) or by cache tag ([`revalidateTag`](/docs/app/api-reference/functions/revalidateTag)).
|
|
|
|
### Prefetching
|
|
|
|
Prefetching is a way to preload a route in the background before it's visited. The rendered result of prefetched routes is added to the router's client-side cache. This makes navigating to a prefetched route near-instant.
|
|
|
|
By default, routes are prefetched as they become visible in the viewport when using the `<Link>` component. This can happen when the page first loads or through scrolling. Routes can also be programmatically prefetched using the `prefetch` method of the [`useRouter()` hook](/docs/app/api-reference/functions/use-router#userouter).
|
|
|
|
**Static and Dynamic Routes**:
|
|
|
|
- If the route is static, all the Server Component payloads for the route segments will be prefetched.
|
|
- If the route is dynamic, the payload from the first shared layout down until the first `loading.js` file is prefetched. This reduces the cost of prefetching the whole route dynamically and allows [instant loading states](/docs/app/building-your-application/routing/loading-ui-and-streaming#instant-loading-states) for dynamic routes.
|
|
|
|
> **Good to know**:
|
|
>
|
|
> - Prefetching is only enabled in production.
|
|
> - Prefetching can be disabled by passing `prefetch={false}` to `<Link>`.
|
|
|
|
### Soft Navigation
|
|
|
|
On navigation, the cache for changed segments is reused (if it exists), and no new requests are made to the server for data.
|
|
|
|
#### Conditions for Soft Navigation
|
|
|
|
On navigation, Next.js will use soft navigation if the route you are navigating to has been [**prefetched**](#prefetching), and either doesn't include [dynamic segments](/docs/app/building-your-application/routing/dynamic-routes) **or** has the same dynamic parameters as the current route.
|
|
|
|
For example, consider the following route that includes a dynamic `[team]` segment: `/dashboard/[team]/*`. The cached segments below `/dashboard/[team]/*` will only be invalidated when the `[team]` parameter changes.
|
|
|
|
- Navigating from `/dashboard/team-red/*` to `/dashboard/team-red/*` will be a soft navigation.
|
|
- Navigating from `/dashboard/team-red/*` to `/dashboard/team-blue/*` will be a hard navigation.
|
|
|
|
### Hard Navigation
|
|
|
|
On navigation, the cache is invalidated and the server refetches data and re-renders the changed segments.
|
|
|
|
### Back/Forward Navigation
|
|
|
|
Back and forward navigation ([popstate event](https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event)) has a soft navigation behavior. This means, the client-side cache is re-used and navigation is near-instant.
|
|
|
|
### Focus and Scroll Management
|
|
|
|
By default, Next.js will set focus and scroll into view the segment that's changed on navigation.
|