連結與導航

在 Next.js 中有兩種方式可以在路由之間進行導航:

本頁將介紹如何使用 <Link>useRouter(),並深入探討導航的運作原理。

<Link> 是一個內建元件,它擴展了 HTML 的 <a> 標籤,提供 預取 (prefetching) 和路由之間的客戶端導航功能。這是 Next.js 中在路由之間導航的主要方式。

你可以從 next/link 導入它,並將 href 屬性傳遞給元件:

import Link from 'next/link'

export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>
}

你還可以傳遞其他可選屬性給 <Link>。詳見 API 參考文件

範例

連結到動態區段

當連結到 動態區段 (dynamic segments) 時,可以使用 模板字面量 (template literals) 和插值 (interpolation) 來生成連結列表。例如,生成部落格文章列表:

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>
  )
}

檢查當前連結

你可以使用 usePathname() 來判斷連結是否處於活動狀態。例如,要為當前活動的連結添加一個類別,可以檢查當前的 pathname 是否與連結的 href 匹配:

'use client'

import { usePathname } from 'next/navigation'
import Link from 'next/link'

export function Links() {
  const pathname = usePathname()

  return (
    <nav>
      <ul>
        <li>
          <Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
            首頁
          </Link>
        </li>
        <li>
          <Link
            className={`link ${pathname === '/about' ? 'active' : ''}`}
            href="/about"
          >
            關於
          </Link>
        </li>
      </ul>
    </nav>
  )
}

滾動到特定 id

Next.js App Router 的預設行為是在導航到新路由時滾動到頁面頂部,或在向前和向後導航時保持滾動位置。

如果你想在導航時滾動到特定的 id,可以在 URL 後添加 # 哈希連結,或直接將哈希連結傳遞給 href 屬性。這是可行的,因為 <Link> 會渲染為 <a> 元素。

<Link href="/dashboard#settings">設定</Link>

// 輸出
<a href="/dashboard#settings">設定</a>

禁用滾動恢復

Next.js App Router 的預設行為是在導航到新路由時滾動到頁面頂部,或在向前和向後導航時保持滾動位置。如果你想禁用此行為,可以將 scroll={false} 傳遞給 <Link> 元件,或將 scroll: false 傳遞給 router.push()router.replace()

// next/link
<Link href="/dashboard" scroll={false}>
  儀表板
</Link>
// useRouter
import { useRouter } from 'next/navigation'

const router = useRouter()

router.push('/dashboard', { scroll: false })

useRouter() 鉤子

useRouter 鉤子允許你以程式化的方式變更路由。

此鉤子僅能在客戶端元件中使用,並從 next/navigation 導入。

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')}>
      儀表板
    </button>
  )
}

有關 useRouter 方法的完整列表,請參閱 API 參考文件

建議: 除非有特定需求需要使用 useRouter,否則請使用 <Link> 元件在路由之間導航。

路由與導航的運作方式

App Router 使用混合方法進行路由和導航。在伺服器端,你的應用程式代碼會根據路由區段自動進行代碼分割。在客戶端,Next.js 會 預取 (prefetch)快取 (cache) 路由區段。這意味著,當用戶導航到新路由時,瀏覽器不會重新加載頁面,只有變更的路由區段會重新渲染 — 從而提升導航體驗和效能。

1. 預取 (Prefetching)

預取是一種在用戶訪問路由前在後台預先加載路由的方式。

Next.js 中有兩種預取路由的方式:

  • <Link> 元件:當路由在用戶的可視區域中可見時,會自動進行預取。預取會在頁面首次加載或通過滾動進入視野時觸發。
  • router.prefetch():可以使用 useRouter 鉤子以程式化的方式預取路由。

<Link> 的預取行為對於靜態和動態路由有所不同:

你可以通過將 prefetch 屬性設為 false 來禁用預取功能。

詳見 <Link> API 參考文件

須知:

  • 預取功能在開發模式下不會啟用,僅在生產環境中有效。

2. 快取 (Caching)

Next.js 有一個稱為 路由快取 (Router Cache)記憶體客戶端快取。當用戶在應用中導航時,預取 的路由區段和已訪問路由的 React 伺服器元件負載會被儲存在快取中。

這意味著在導航時,快取會盡可能被重用,而不是向伺服器發送新的請求 — 通過減少請求和傳輸的數據量來提升效能。

了解更多關於 路由快取 (Router Cache) 的運作方式以及如何配置它。

3. 部分渲染 (Partial Rendering)

部分渲染意味著在導航時,只有變更的路由區段會在客戶端重新渲染,而任何共享的區段會被保留。

例如,當在兩個兄弟路由 /dashboard/settings/dashboard/analytics 之間導航時,settingsanalytics 頁面會被渲染,而共享的 dashboard 佈局會被保留。

部分渲染的運作方式

如果沒有部分渲染,每次導航都會導致伺服器重新渲染整個頁面。僅渲染變更的區段減少了傳輸的數據量和執行時間,從而提升了效能。

4. 軟導航 (Soft Navigation)

預設情況下,瀏覽器會在頁面之間執行硬導航。這意味著瀏覽器會重新加載頁面並重置 React 狀態,例如應用中的 useState 鉤子,以及瀏覽器狀態,例如用戶的滾動位置或聚焦元素。然而,在 Next.js 中,App Router 使用軟導航。這意味著 React 只會渲染變更的區段,同時保留 React 和瀏覽器狀態,並且不會進行完整的頁面重新加載。

5. 向後和向前導航

預設情況下,Next.js 會在向後和向前導航時保持滾動位置,並重用 路由快取 (Router Cache) 中的路由區段。

On this page