跳到內容

連結與導航

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`

視口中(最初或透過滾動)的任何 `` 都會預設被預取(包括相應的資料),用於使用靜態生成的頁面。對於伺服器渲染路由,相應的資料僅在點選 `` 時獲取。

連結到動態路徑

你還可以使用插值來建立路徑,這對於動態路由段非常有用。例如,要顯示一個作為 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 物件,其中

  • `pathname` 是 `pages` 目錄中頁面的名稱。在本例中是 `/blog/[slug]`。
  • `query` 是一個包含動態段的物件。在本例中是 `slug`。

注入路由

要在 React 元件中訪問`router` 物件,可以使用`useRouter``withRouter`

通常,我們建議使用`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 而無需再次執行資料獲取方法,這包括`getServerSideProps``getStaticProps``getInitialProps`

你將透過`router` 物件(由`useRouter``withRouter`新增)接收更新後的 `pathname` 和 `query`,而不會丟失狀態。

要啟用淺層路由,請將 `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 })

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

當淺層路由與代理一起使用時,它將無法像以前沒有代理時那樣確保新頁面與當前頁面匹配。這是因為代理可以動態重寫,並且在不進行資料獲取(淺層路由跳過了資料獲取)的情況下無法在客戶端驗證,因此淺層路由更改必須始終被視為淺層路由。