コンテンツへスキップ

<Link>

<Link>は、HTMLの<a>要素を拡張してプリフェッチと、ルート間のクライアントサイドナビゲーションを提供するReactコンポーネントです。Next.jsでルート間を移動する主な方法です。

基本的な使い方

app/page.tsx
import Link from 'next/link'
 
export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>
}

リファレンス

<Link>コンポーネントには、以下のプロパティを渡すことができます。

プロパティ必須
hrefhref="/dashboard"文字列またはオブジェクトはい
replacereplace={false}ブール値-
scrollscroll={false}ブール値-
prefetchprefetch={false}ブール値またはnull-

覚えておくと良い点: classNametarget="_blank"などの<a>タグ属性は、プロパティとして<Link>に追加でき、基になる<a>要素に渡されます。

href (必須)

移動先のパスまたはURL。

app/page.tsx
import Link from 'next/link'
 
// Navigate to /about?name=test
export default function Page() {
  return (
    <Link
      href={{
        pathname: '/about',
        query: { name: 'test' },
      }}
    >
      About
    </Link>
  )
}

replace

デフォルトはfalseです。trueの場合、next/linkは現在の履歴状態を置き換える代わりに、ブラウザの履歴スタックに新しいURLを追加しません。

app/page.tsx
import Link from 'next/link'
 
export default function Page() {
  return (
    <Link href="/dashboard" replace>
      Dashboard
    </Link>
  )
}

scroll

デフォルトはtrueです。Next.jsにおける<Link>のデフォルトのスクロール動作は、ブラウザの前後ナビゲーションと同様に、スクロール位置を維持することです。新しいページに移動すると、ページがビューポートに表示されている限り、スクロール位置は変わりません。ただし、ページがビューポートに表示されていない場合、Next.jsは最初のページ要素の先頭にスクロールします。

scroll = {false}の場合、Next.jsは最初のページ要素にスクロールしようとせず、スクロール位置はそのまま維持されます。

app/page.tsx
import Link from 'next/link'
 
export default function Page() {
  return (
    <Link href="/dashboard" scroll={false}>
      Dashboard
    </Link>
  )
}

prefetch

プリフェッチは、<Link /> コンポーネントがユーザーのビューポートに表示された時(最初に表示された時、またはスクロールによって表示された時)に発生します。Next.js は、リンクされたルート(href で指定)とそのデータをバックグラウンドでプリフェッチして読み込み、クライアント側のナビゲーションのパフォーマンスを向上させます。プリフェッチされたデータが、ユーザーが <Link /> にカーソルを合わせた時点で期限切れになっている場合、Next.js は再度プリフェッチを試みます。**プリフェッチは本番環境でのみ有効です。**

prefetch プロパティには、次の値を渡すことができます。

  • null(デフォルト): プリフェッチの動作は、ルートが静的か動的なかに依存します。静的ルートの場合、ルート全体(すべてのデータを含む)がプリフェッチされます。動的ルートの場合、loading.js境界を持つ最も近いセグメントまでの部分的なルートがプリフェッチされます。
  • true: 静的ルートと動的ルートの両方で、ルート全体がプリフェッチされます。
  • false: ビューポートへの表示時とホバー時の両方で、プリフェッチは決して発生しません。
app/page.tsx
import Link from 'next/link'
 
export default function Page() {
  return (
    <Link href="/dashboard" prefetch={false}>
      Dashboard
    </Link>
  )
}

次の例は、さまざまなシナリオで<Link>コンポーネントを使用する方法を示しています。

動的セグメントへのリンク

動的セグメントにリンクする場合は、テンプレートリテラルと補間を使用してリンクのリストを生成できます。たとえば、ブログ投稿のリストを生成するには

app/blog/post-list.tsx
import Link from 'next/link'
 
interface Post {
  id: number
  title: string
  slug: string
}
 
export default function PostList({ posts }: { posts: Post[] }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

usePathname() を使用して、リンクがアクティブかどうかを判断できます。たとえば、アクティブなリンクにクラスを追加するには、現在の pathname がリンクの href と一致するかどうかを確認します。

app/ui/nav-links.tsx
'use client'
 
import { usePathname } from 'next/navigation'
import Link from 'next/link'
 
export function Links() {
  const pathname = usePathname()
 
  return (
    <nav>
      <Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
        Home
      </Link>
 
      <Link
        className={`link ${pathname === '/about' ? 'active' : ''}`}
        href="/about"
      >
        About
      </Link>
    </nav>
  )
}

idへのスクロール

ナビゲーション時に特定のidにスクロールしたい場合は、URLに#ハッシュリンクを追加するか、ハッシュリンクをhrefプロパティに渡すことができます。これは、<Link><a>要素にレンダリングされるため可能です。

<Link href="/dashboard#settings">Settings</Link>
 
// Output
<a href="/dashboard#settings">Settings</a>

知っておくと良いこと:

  • ナビゲーション時にページがビューポートに表示されていない場合、Next.js はページの先頭にスクロールします。

動的ルートセグメントへのリンク

動的ルートセグメントでは、テンプレートリテラルを使用してリンクのパスを作成すると便利です。

たとえば、動的ルートapp/blog/[slug]/page.jsへのリンクのリストを生成できます。

app/blog/page.tsx
import Link from 'next/link'
 
export default function Page({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

子が<a>タグをラップするカスタムコンポーネントである場合

Linkの子が<a>タグをラップするカスタムコンポーネントである場合、LinkpassHrefを追加する必要があります。これは、styled-componentsなどのライブラリを使用している場合に必要です。これがないと、<a>タグにhref属性がなくなり、サイトのアクセシビリティが低下し、SEOに影響を与える可能性があります。ESLintを使用している場合、passHrefの正しい使用方法を確保するための組み込みルールnext/link-passhrefがあります。

components/nav-link.tsx
import Link from 'next/link'
import styled from 'styled-components'
 
// This creates a custom component that wraps an <a> tag
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プラグマ機能(@jsx jsx)を使用している場合、<a>タグを直接使用していても、passHrefを使用する必要があります。
  • コンポーネントは、ナビゲーションを正しくトリガーするためのonClickプロパティをサポートする必要があります。

関数型コンポーネントのネスト

Linkの子が関数型コンポーネントである場合、passHreflegacyBehaviorを使用することに加えて、コンポーネントをReact.forwardRefでラップする必要があります。

app/page.tsx
import Link from 'next/link'
import React from 'react'
 
// Define the props type for MyButton
interface MyButtonProps {
  onClick?: React.MouseEventHandler<HTMLAnchorElement>
  href?: string
}
 
// Use React.ForwardRefRenderFunction to properly type the forwarded ref
const MyButton: React.ForwardRefRenderFunction<
  HTMLAnchorElement,
  MyButtonProps
> = ({ onClick, href }, ref) => {
  return (
    <a href={href} onClick={onClick} ref={ref}>
      Click Me
    </a>
  )
}
 
// Use React.forwardRef to wrap the component
const ForwardedMyButton = React.forwardRef(MyButton)
 
export default function Page() {
  return (
    <Link href="/about" passHref legacyBehavior>
      <ForwardedMyButton />
    </Link>
  )
}

URLの置換ではなくプッシュ

Linkコンポーネントのデフォルトの動作は、新しいURLをhistoryスタックにpushすることです。次の例のように、replaceプロパティを使用して新しいエントリの追加を防ぐことができます。

app/page.js
import Link from 'next/link'
 
export default function Page() {
  return (
    <Link href="/about" replace>
      About us
    </Link>
  )
}

ページの先頭へのスクロールの無効化

Next.jsの<Link>のデフォルトのスクロール動作は、ブラウザが前後のナビゲーションを処理する方法と同様に、**スクロール位置を維持すること**です。新しいページに移動すると、ページがビューポートに表示されている限り、スクロール位置は変わりません。

しかし、ページがビューポートに表示されていない場合、Next.jsは最初のページ要素の先頭にスクロールします。この動作を無効にするには、<Link>コンポーネントにscroll={false}、またはrouter.push()またはrouter.replace()scroll: falseを渡すことができます。

app/page.tsx
import Link from 'next/link'
 
export default function Page() {
  return (
    <Link href="/#hashid" scroll={false}>
      Disables scrolling to the top
    </Link>
  )
}

router.push()またはrouter.replace()の使用

// useRouter
import { useRouter } from 'next/navigation'
 
const router = useRouter()
 
router.push('/dashboard', { scroll: false })

認証や、ユーザーを別のページに書き換えることを含むその他の目的のためにミドルウェアを使用することが一般的です。<Link />コンポーネントがミドルウェアによる書き換えでリンクを適切にプリフェッチするためには、表示するURLとプリフェッチするURLの両方をNext.jsに伝える必要があります。これは、プリフェッチする正しいルートを知るためにミドルウェアへの不要なフェッチを回避するために必要です。

たとえば、認証されたビューと訪問者ビューを持つ/dashboardルートを提供する場合、ミドルウェアに次のコードを追加して、ユーザーを正しいページにリダイレクトできます。

middleware.ts
import { NextResponse } from 'next/server'
 
export function middleware(request: Request) {
  const nextUrl = request.nextUrl
  if (nextUrl.pathname === '/dashboard') {
    if (request.cookies.authToken) {
      return NextResponse.rewrite(new URL('/auth/dashboard', request.url))
    } else {
      return NextResponse.rewrite(new URL('/public/dashboard', request.url))
    }
  }
}
middleware.js
import { NextResponse } from 'next/server'
 
export function middleware(request) {
  const nextUrl = request.nextUrl
  if (nextUrl.pathname === '/dashboard') {
    if (request.cookies.authToken) {
      return NextResponse.rewrite(new URL('/auth/dashboard', request.url))
    } else {
      return NextResponse.rewrite(new URL('/public/dashboard', request.url))
    }
  }
}

この場合、<Link />コンポーネントで次のコードを使用する必要があります。

app/page.tsx
'use client'
 
import Link from 'next/link'
import useIsAuthed from './hooks/useIsAuthed' // Your auth hook
 
export default function Page() {
  const isAuthed = useIsAuthed()
  const path = isAuthed ? '/auth/dashboard' : '/public/dashboard'
  return (
    <Link as="/dashboard" href href={path}>
      Dashboard
    </Link>
  )
}

バージョン履歴

バージョン変更点
v13.0.0子要素の<a>タグが不要になりました。コードベースを自動的に更新するためのcodemodを提供しています。
v10.0.0動的ルートを指すhrefプロパティは自動的に解決されるようになり、asプロパティは不要になりました。
v8.0.0プリフェッチのパフォーマンスが向上しました。
v1.0.0next/linkが導入されました。