<Link>

範例

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

舉例來說,假設有一個包含以下文件的 pages 目錄:

  • pages/index.js
  • pages/about.js
  • pages/blog/[slug].js

我們可以像這樣為每個頁面建立連結:

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

屬性

以下是 Link 元件可用的屬性摘要:

屬性範例類型必填
hrefhref="/dashboard"字串或物件
replacereplace={false}布林值-
scrollscroll={false}布林值-
prefetchprefetch={false}布林值-

須知<a> 標籤的屬性如 classNametarget="_blank" 可以作為屬性添加到 <Link> 中,並會傳遞給底層的 <a> 元素。

href (必填)

要導航至的路徑或 URL。

<Link href="/dashboard">儀表板</Link>

href 也可以接受物件,例如:

// 導航至 /about?name=test
<Link
  href={{
    pathname: '/about',
    query: { name: 'test' },
  }}
>
  關於
</Link>

replace

預設為 false 當設為 true 時,next/link 會替換當前的歷史狀態,而不是在 瀏覽器的歷史記錄 堆疊中新增一個 URL。

import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/dashboard" replace>
      儀表板
    </Link>
  )
}

scroll

預設為 true <Link> 的預設行為是 滾動到新路由的頂部或維持後退和前進導航的滾動位置。 當設為 false 時,next/link 在導航後 不會 滾動到頁面頂部。

import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/dashboard" scroll={false}>
      儀表板
    </Link>
  )
}

須知

  • 如果導航時 頁面 不在視窗的可見範圍內,Next.js 會滾動到該頁面。

prefetch

<Link /> 元件進入使用者的視窗(初始或通過滾動)時,預取就會發生。Next.js 會在背景預取並載入連結的路由(由 href 表示)和資料,以提高客戶端導航的性能。預取僅在生產環境中啟用。

  • true (預設):將預取完整路由及其資料。
  • false:進入視窗時不會進行預取,但懸停時會進行。如果您想完全移除懸停時的預取,可以考慮使用 <a> 標籤或 逐步採用 應用程式路由,後者也允許禁用懸停時的預取。
import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/dashboard" prefetch={false}>
      儀表板
    </Link>
  )
}

其他屬性

legacyBehavior

<Link> 的子元素不再需要 <a> 元素。添加 legacyBehavior 屬性以使用舊行為,或移除 <a> 以升級。提供了一個 程式碼修改工具 (codemod) 來自動升級您的程式碼。

須知:當 legacyBehavior 未設為 true 時,所有 anchor 標籤的屬性都可以傳遞給 next/link,例如 classNameonClick 等。

passHref

強制 Linkhref 屬性傳遞給其子元素。預設為 false

scroll

導航後滾動到頁面頂部。預設為 true

shallow

更新當前頁面的路徑而不重新執行 getStaticPropsgetServerSidePropsgetInitialProps。預設為 false

locale

會自動添加當前使用的語言設定。locale 允許提供不同的語言設定。當設為 false 時,href 必須包含語言設定,因為預設行為被禁用。

範例

連結到動態路由

對於動態路由,使用模板字面量來建立連結的路徑會很方便。

例如,您可以生成一個指向動態路由 pages/blog/[slug].js 的連結列表:

pages/blog/index.js
import Link from 'next/link'

function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

export default Posts

如果子元素是包裹 <a> 標籤的自訂元件

如果 Link 的子元素是包裹 <a> 標籤的自訂元件,您必須向 Link 添加 passHref。如果您使用像 styled-components 這樣的函式庫,這是必要的。沒有這個,<a> 標籤將不會有 href 屬性,這會損害您網站的可訪問性並可能影響 SEO。如果您使用 ESLint,有一個內建的規則 next/link-passhref 來確保正確使用 passHref

import Link from 'next/link'
import styled from 'styled-components'

// 這創建了一個包裹 <a> 標籤的自訂元件
const RedLink = styled.a`
  color: red;
`

function NavLink({ href, name }) {
  return (
    <Link href={href} passHref legacyBehavior>
      <RedLink>{name}</RedLink>
    </Link>
  )
}

export default NavLink
  • 如果您使用 emotion 的 JSX pragma 功能 (@jsx jsx),即使直接使用 <a> 標籤,也必須使用 passHref
  • 元件應支援 onClick 屬性以正確觸發導航

如果子元素是函式元件

如果 Link 的子元素是函式元件,除了使用 passHreflegacyBehavior 外,您還必須將元件包裹在 React.forwardRef 中:

import Link from 'next/link'

// `onClick`、`href` 和 `ref` 需要傳遞給 DOM 元素
// 以進行正確處理
const MyButton = React.forwardRef(({ onClick, href }, ref) => {
  return (
    <a href={href} onClick={onClick} ref={ref}>
      點擊我
    </a>
  )
})

function Home() {
  return (
    <Link href="/about" passHref legacyBehavior>
      <MyButton />
    </Link>
  )
}

export default Home

使用 URL 物件

Link 也可以接收 URL 物件,它會自動格式化以建立 URL 字串。以下是操作方法:

import Link from 'next/link'

function Home() {
  return (
    <ul>
      <li>
        <Link
          href={{
            pathname: '/about',
            query: { name: 'test' },
          }}
        >
          關於我們
        </Link>
      </li>
      <li>
        <Link
          href={{
            pathname: '/blog/[slug]',
            query: { slug: 'my-post' },
          }}
        >
          部落格文章
        </Link>
      </li>
    </ul>
  )
}

export default Home

上面的範例有兩個連結:

  • 預定義路由:/about?name=test
  • 動態路由/blog/my-post

您可以使用 Node.js URL 模組文件 中定義的所有屬性。

替換 URL 而不是推送

Link 元件的預設行為是將新 URL pushhistory 堆疊中。您可以使用 replace 屬性來防止新增條目,如下例所示:

<Link href="/about" replace>
  關於我們
</Link>

禁用滾動到頁面頂部

Link 的預設行為是滾動到頁面頂部。當定義了 hash 時,它會滾動到特定的 id,就像普通的 <a> 標籤一樣。要防止滾動到頂部 / hash,可以將 scroll={false} 添加到 Link

<Link href="/#hashid" scroll={false}>
  禁用滾動到頂部
</Link>

中介軟體 (Middleware)

通常會使用 中介軟體 (Middleware) 進行身份驗證或其他涉及將使用者重寫到不同頁面的用途。為了讓 <Link /> 元件能正確預取通過中介軟體重寫的連結,您需要告訴 Next.js 要顯示的 URL 和要預取的 URL。這是為了避免不必要的向中介軟體發送請求以了解要預取的正確路由。

例如,如果您想提供一個具有已驗證和訪客視圖的 /dashboard 路由,您可以在中介軟體中添加類似以下的內容,以將使用者重定向到正確的頁面:

middleware.js
export function middleware(req) {
  const nextUrl = req.nextUrl
  if (nextUrl.pathname === '/dashboard') {
    if (req.cookies.authToken) {
      return NextResponse.rewrite(new URL('/auth/dashboard', req.url))
    } else {
      return NextResponse.rewrite(new URL('/public/dashboard', req.url))
    }
  }
}

在這種情況下,您需要在 <Link /> 元件中使用以下程式碼:

import Link from 'next/link'
import useIsAuthed from './hooks/useIsAuthed'

export default function Page() {
  const isAuthed = useIsAuthed()
  const path = isAuthed ? '/auth/dashboard' : '/public/dashboard'
  return (
    <Link as="/dashboard" href={path}>
      儀表板
    </Link>
  )
}

須知:如果您使用 動態路由,您需要調整 ashref 屬性。例如,如果您有一個像 /dashboard/authed/[user] 這樣的動態路由,想要通過中介軟體以不同方式呈現,您會這樣寫:<Link href={{ pathname: '/dashboard/authed/[user]', query: { user: username } }} as="/dashboard/[user]">個人資料</Link>

版本歷史

版本變更內容
v13.0.0不再需要子 <a> 標籤。提供了一個 codemod 來自動更新您的程式碼庫。
v10.0.0指向動態路由的 href 屬性現在會自動解析,不再需要 as 屬性。
v8.0.0改進了預取 (prefetching) 效能。
v1.0.0引入 next/link