Linking and Navigating 链接和导航

There are four ways to navigate between routes in Next.js:

在 Next.js 中有四种在路由之间导航的方法:

  • Using the <Link> Component
    使用 <Link> 组件

  • Using the useRouter hook (Client Components)
    使用 useRouter 钩子(客户端组件)

  • Using the redirect function (Server Components)
    使用 redirect 函数(服务器组件)

  • Using the native History API
    使用原生 History API

This page will go through how to use each of these options, and dive deeper into how navigation works.

本页将介绍如何使用这些选项,并深入探讨导航的工作原理。

1.<Link>Component 组件

<Link> is a built-in component that extends the HTML <a> tag to provide prefetching and client-side navigation between routes. It is the primary and recommended way to navigate between routes in Next.js.

<Link> 是一个内置组件,它扩展了 HTML <a> 标签,以便在路由之间提供预取和客户端导航。它是 Next.js 中在路由之间导航的主要推荐方式。

You can use it by importing it from next/link, and passing a href prop to the component:

您可以通过从 next/link 导入它,并将 href prop 传递给组件来使用它:

import Link from 'next/link'
 
export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>
}

There are other optional props you can pass to <Link>. See the API reference for more.

您可以传递给 <Link> 的其他可选属性。有关更多信息,请参阅 API 参考。

2.useRouter() hook

The useRouter hook allows you to programmatically change routes from Client Components.

您可以使用 useRouter 钩子通过客户端组件以编程方式更改路由。

'use client'
 
import { useRouter } from 'next/navigation'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}

For a full list of useRouter methods, see the API reference.

有关 useRouter 方法的完整列表,请参阅 API 参考。

3.redirect function redirect 函数

For Server Components, use the redirect function instead.

对于服务器组件,请改用 redirect 函数。

import { redirect } from 'next/navigation'
 
async function fetchTeam(id: string) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}
 
export default async function Profile({ params }: { params: { id: string } }) {
  const team = await fetchTeam(params.id)
  if (!team) {
    redirect('/login')
  }
 
  // ...
}

Good to know: 值得了解:

  • redirect returns a 307 (Temporary Redirect) status code by default. When used in a Server Action, it returns a 303 (See Other), which is commonly used for redirecting to a success page as a result of a POST request.
    redirect 默认返回 307(临时重定向)状态代码。当在服务器操作中使用时,它返回 303(另请参阅),通常用于在 POST 请求的结果中重定向到成功页面。

  • redirect internally throws an error so it should be called outside of try/catch blocks.
    redirect 内部引发错误,因此应在 try/catch 块之外调用它。

  • redirect can be called in Client Components during the rendering process but not in event handlers. You can use the useRouter hook instead.
    redirect 可以在渲染过程中在客户端组件中调用,但不能在事件处理程序中调用。您可以改用 useRouter 钩子。

  • redirect also accepts absolute URLs and can be used to redirect to external links.
    redirect 也接受绝对 URL,可用于重定向到外部链接。

  • If you'd like to redirect before the render process, use next.config.js or Middleware.
    如果您想在渲染过程之前重定向,请使用 next.config.js 或中间件。

4.Using the native History API 使用原生 History API

Next.js allows you to use the native window.history.pushState and window.history.replaceState methods to update the browser's history stack without reloading the page.

Next.js 允许您使用原生的 window.history.pushState 和 window.history.replaceState 方法来更新浏览器的历史记录堆栈,而无需重新加载页面。

pushState and replaceState calls integrate into the Next.js Router, allowing you to sync with usePathname and useSearchParams.

pushState 和 replaceState 调用集成到 Next.js 路由器中,允许您与 usePathname 和 useSearchParams 同步。

a.window.history.pushState

Use it to add a new entry to the browser's history stack. The user can navigate back to the previous state. For example, to sort a list of products:

使用它向浏览器的历史记录堆栈添加新条目。用户可以导航回上一个状态。例如,对产品列表进行排序:

'use client'
 
import { useSearchParams } from 'next/navigation'
 
export default function SortProducts() {
  const searchParams = useSearchParams()
 
  function updateSorting(sortOrder: string) {
    const params = new URLSearchParams(searchParams.toString())
    params.set('sort', sortOrder)
    window.history.pushState(null, '', `?${params.toString()}`)
  }
 
  return (
    <>
      <button onClick={() => updateSorting('asc')}>Sort Ascending</button>
      <button onClick={() => updateSorting('desc')}>Sort Descending</button>
    </>
  )
}

b.window.history.replaceState

Use it to replace the current entry on the browser's history stack. The user is not able to navigate back to the previous state. For example, to switch the application's locale:

使用它替换浏览器历史记录堆栈中的当前条目。用户无法导航回上一个状态。例如,要切换应用程序的语言环境:

'use client'
 
import { usePathname } from 'next/navigation'
 
export function LocaleSwitcher() {
  const pathname = usePathname()
 
  function switchLocale(locale: string) {
    // e.g. '/en/about' or '/fr/contact'
    const newPath = `/${locale}${pathname}`
    window.history.replaceState(null, '', newPath)
  }
 
  return (
    <>
      <button onClick={() => switchLocale('en')}>English</button>
      <button onClick={() => switchLocale('fr')}>French</button>
    </>
  )
}

5.How Routing and Navigation Works 路由和导航的工作原理

The App Router uses a hybrid approach for routing and navigation. On the server, your application code is automatically code-split by route segments. And on the client, Next.js prefetches and caches the route segments. This means, when a user navigates to a new route, the browser doesn't reload the page, and only the route segments that change re-render - improving the navigation experience and performance.

App Router 采用混合方法进行路由和导航。在服务器上,您的应用程序代码会自动按路由段进行代码拆分。在客户端,Next.js 会预取并缓存路由段。这意味着,当用户导航到新路由时,浏览器不会重新加载页面,只有发生变化的路由段才会重新渲染 - 从而改善导航体验和性能。

a.Code Splitting 代码拆分

Code splitting allows you to split your application code into smaller bundles to be downloaded and executed by the browser. This reduces the amount of data transferred and execution time for each request, leading to improved performance.

代码拆分允许您将应用程序代码拆分为更小的包,以便浏览器下载并执行。这减少了每次请求的数据传输量和执行时间,从而提高了性能。

Server Components allow your application code to be automatically code-split by route segments. This means only the code needed for the current route is loaded on navigation.

服务器组件允许您的应用程序代码按路由段自动进行代码拆分。这意味着在导航时只加载当前路由所需的代码。

b.Prefetching 预取

Prefetching is a way to preload a route in the background before the user visits it.

预取是一种在用户访问之前在后台预加载路由的方式。

There are two ways routes are prefetched in Next.js:

Next.js 中有两种预取路由的方式:

-<Link> component: Routes are automatically prefetched as they become visible in the user's viewport. Prefetching happens when the page first loads or when it comes into view through scrolling.

<Link> 组件:当路由在用户视口中可见时,它们会自动预取。预取发生在页面首次加载时或通过滚动进入视图时。

ps: 这个也是为啥页面的路由导航中,建议使用link的原因,因为会自动进行预加载。

-router.prefetch(): The useRouter hook can be used to prefetch routes programmatically.

router.prefetch() : useRouter 挂钩可用于以编程方式预取路由。

The<Link>'s prefetching behavior is different for static and dynamic routes:

对于静态和动态路由, <Link> 的预取行为不同:

-Static Routes: prefetch defaults to true. The entire route is prefetched and cached.

静态路由: prefetch 默认为 true 。整个路由都将被预取并缓存。

-Dynamic Routes: prefetch default to automatic. Only the shared layout, down the rendered "tree" of components until the first loading.js file, is prefetched and cached for 30s. This reduces the cost of fetching an entire dynamic route, and it means you can show an instant loading state for better visual feedback to users.

动态路由: prefetch 默认为自动。只有共享布局,直到第一个 loading.js 文件的已渲染“树”,才会被预取并缓存 30s 。这减少了获取整个动态路由的成本,这意味着您可以显示即时加载状态,以便为用户提供更好的视觉反馈。

You can disable prefetching by setting the prefetch prop to false.

您可以通过将 prefetch 属性设置为 false 来禁用预取。

c.Caching 缓存

Next.js has an in-memory client-side cache called the Router Cache. As users navigate around the app, the React Server Component Payload of prefetched route segments and visited routes are stored in the cache.

Next.js 有一个称为路由器缓存的内存中客户端缓存。当用户在应用程序中导航时,预取路由段和已访问路由的 React 服务器组件负载会存储在缓存中。

This means on navigation, the cache is reused as much as possible, instead of making a new request to the server - improving performance by reducing the number of requests and data transferred.

这意味着在导航时,尽可能地重复使用缓存,而不是向服务器发出新的请求 - 通过减少请求和传输的数据量来提高性能。

d.Partial Rendering 部分渲染

Partial rendering means only the route segments that change on navigation re-render on the client, and any shared segments are preserved.

部分渲染意味着在客户端上仅重新渲染导航时更改的路由段,并且保留任何共享段。

For example, when navigating between two sibling routes, /dashboard/settings and /dashboard/analytics, the settings and analytics pages will be rendered, and the shared dashboard layout will be preserved.

例如,在两个兄弟路由 /dashboard/settings 和 /dashboard/analytics 之间导航时,将渲染 settings 和 analytics 页面,并将保留共享的 dashboard 布局。

Without partial rendering, each navigation would cause the full page to re-render on the client. Rendering only the segment that changes reduces the amount of data transferred and execution time, leading to improved performance.

如果没有部分渲染,每次导航都会导致客户端重新渲染整个页面。仅渲染发生变化的部分可以减少传输的数据量和执行时间,从而提高性能。

e.Soft Navigation 软导航

Browsers perform a "hard navigation" when navigating between pages. The Next.js App Router enables "soft navigation" between pages, ensuring only the route segments that have changed are re-rendered (partial rendering). This enables client React state to be preserved during navigation.

浏览器在页面之间导航时会执行“硬导航”。Next.js App Router 允许在页面之间进行“软导航”,确保只重新渲染已更改的路由段(部分渲染)。这使得在导航期间保留客户端 React 状态成为可能。

f.Back and Forward Navigation 后退和前进导航

By default, Next.js will maintain the scroll position for backwards and forwards navigation, and re-use route segments in the Router Cache.

默认情况下,Next.js 将维护后退和前进导航的滚动位置,并在路由缓存中重新使用路由段。

h.Routing between pages/ and app/ 在 pages/ 和 app/ 之间的路由

When incrementally migrating from pages/ to app/, the Next.js router will automatically handle hard navigation between the two. To detect transitions from pages/ to app/, there is a client router filter that leverages probabilistic checking of app routes, which can occasionally result in false positives. By default, such occurrences should be very rare, as we configure the false positive likelihood to be 0.01%. This likelihood can be customized via the experimental.clientRouterFilterAllowedRate option in next.config.js. It's important to note that lowering the false positive rate will increase the size of the generated filter in the client bundle.

在从 pages/ 增量迁移到 app/ 时,Next.js 路由器将自动处理两者之间的硬导航。为了检测从 pages/ 到 app/ 的过渡,有一个客户端路由器过滤器,它利用应用程序路由的概率检查,偶尔会导致误报。默认情况下,此类情况应该非常罕见,因为我们将误报可能性配置为 0.01%。此可能性可以通过 next.config.js 中的 experimental.clientRouterFilterAllowedRate 选项进行自定义。需要注意的是,降低误报率会增加客户端包中生成的过滤器的体积。

Alternatively, if you prefer to disable this handling completely and manage the routing between pages/ and app/ manually, you can set experimental.clientRouterFilter to false in next.config.js. When this feature is disabled, any dynamic routes in pages that overlap with app routes won't be navigated to properly by default.

或者,如果您更愿意完全禁用此处理并手动管理 pages/ 和 app/ 之间的路由,则可以在 next.config.js 中将 experimental.clientRouterFilter 设置为 false。禁用此功能后,默认情况下,页面中与应用路由重叠的任何动态路由都无法正确导航。