跳到主要內容

連結與導航

Next.js 路由器讓您可以在頁面之間進行客戶端路由轉換,類似於單頁應用程式。

Next.js 提供一個名為 Link 的 React 元件來進行這種客戶端路由轉換。

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

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

  • / → pages/index.js
  • /about → pages/about.js
  • /blog/hello-world → pages/blog/[slug].js

任何在可視範圍內的 <Link /> (初始或透過滾動) 都會預先擷取 (包括對應的資料),用於使用靜態產生的頁面。伺服器渲染路由的對應資料*僅在*點擊 <Link /> 時才會擷取。

連結到動態路徑

您也可以使用插值來建立路徑,這對於動態路由區段非常方便。例如,顯示作為 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 object,您可以使用 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')}>
      Click here to read more
    </button>
  )
}

淺層路由

範例

淺層路由允許您在不再次執行資料擷取方法的情況下更改 URL,包括 getServerSidePropsgetStaticPropsgetInitialProps

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

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

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

URL 將更新為 /?counter=10,並且頁面不會被替換,只有路由的狀態會被更改。

您也可以透過如下所示的 componentDidUpdate 監看 URL 更改

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

注意事項

淺層路由**僅**適用於當前頁面中的 URL 更改。 例如,假設我們有另一個名為 pages/about.js 的頁面,並且您執行此操作

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

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

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