連結與導航

Next.js 的路由器 (router) 允許您在頁面之間進行客戶端路由轉換,類似於單頁應用程式 (SPA)。

系統提供了一個名為 Link 的 React 元件來實現這種客戶端路由轉換。

import Link from 'next/link'

function Home() {
  return (
    <ul>
      <li>
        <Link href="/">首頁</Link>
      </li>
      <li>
        <Link href="/about">關於我們</Link>
      </li>
      <li>
        <Link href="/blog/hello-world">部落格文章</Link>
      </li>
    </ul>
  )
}

export default Home

上面的範例使用了多個連結。每個連結都將路徑 (href) 映射到已知頁面:

  • /pages/index.js
  • /aboutpages/about.js
  • /blog/hello-worldpages/blog/[slug].js

視窗內任何 <Link />(初始或透過滾動出現)都會預設預先載入 (prefetched) 使用靜態生成 (Static Generation) 的頁面(包括對應的資料)。而伺服器渲染 (server-rendered) 路由的對應資料,僅在點擊 <Link /> 時才會獲取。

連結到動態路徑

您也可以使用插值來建立路徑,這對於動態路由區段 (dynamic route segments) 非常有用。例如,要顯示作為 prop 傳遞給元件的文章列表:

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 來保持路徑的 utf-8 相容性。

或者,使用 URL 物件:

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

現在,我們不再使用插值來建立路徑,而是在 href 中使用 URL 物件,其中:

  • pathnamepages 目錄中的頁面名稱。本例中為 /blog/[slug]
  • query 是包含動態區段的物件。本例中為 slug

注入路由器

範例

要在 React 元件中存取 router 物件,您可以使用 useRouterwithRouter

一般情況下,我們推薦使用 useRouter

命令式路由

範例

next/link 應該能滿足大多數路由需求,但您也可以在不使用它的情況下進行客戶端導航,請參閱 next/router 文件

以下範例展示如何使用 useRouter 進行基本頁面導航:

import { useRouter } from 'next/router'

export default function ReadMore() {
  const router = useRouter()

  return (
    <button onClick={() => router.push('/about')}>
      點擊此處閱讀更多
    </button>
  )
}

淺層路由

範例

淺層路由 (Shallow routing) 允許您變更 URL 而不再次執行資料獲取方法,這包括 getServerSidePropsgetStaticPropsgetInitialProps

您將透過 router 物件(由 useRouterwithRouter 添加)接收更新的 pathnamequery,而不會丟失狀態。

要啟用淺層路由,請將 shallow 選項設為 true。考慮以下範例:

import { useEffect } from 'react'
import { useRouter } from 'next/router'

// 當前 URL 是 '/'
function Page() {
  const router = useRouter()

  useEffect(() => {
    // 總是在首次渲染後進行導航
    router.push('/?counter=10', undefined, { shallow: true })
  }, [])

  useEffect(() => {
    // 計數器變更了!
  }, [router.query.counter])
}

export default Page

URL 將更新為 /?counter=10 且頁面不會被替換,僅路由狀態會變更。

您也可以透過 componentDidUpdate 監聽 URL 變更,如下所示:

componentDidUpdate(prevProps) {
  const { pathname, query } = this.props.router
  // 驗證 props 是否已變更以避免無限循環
  if (query.counter !== prevProps.router.query.counter) {
    // 根據新查詢獲取資料
  }
}

注意事項

淺層路由適用於當前頁面的 URL 變更。例如,假設我們有另一個名為 pages/about.js 的頁面,您執行以下操作:

router.push('/?counter=10', '/about?counter=10', { shallow: true })

由於這是一個新頁面,它將卸載當前頁面,載入新頁面並等待資料獲取,即使我們要求進行淺層路由。

當淺層路由與中介軟體 (middleware) 一起使用時,它不會像之前沒有中介軟體時那樣確保新頁面與當前頁面匹配。這是因為中介軟體能夠動態重寫,並且在沒有資料獲取的情況下無法在客戶端驗證(淺層路由會跳過資料獲取),因此淺層路由變更必須始終被視為淺層的。

On this page