コンテンツにスキップ

リンクとナビゲーション

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 />` がクリックされた場合*のみ*フェッチされます。

動的パスへのリンク

動的ルートセグメントに便利な、パスを作成するための補間も使用できます。たとえば、コンポーネントにプロップとして渡された投稿のリストを表示するには、次のようにします。

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

パスをUTF-8互換にするために、例では`encodeURIComponent` が使用されています。

または、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>
  )
}

シャロールーティング

シャロールーティングを使用すると、`getServerSideProps``getStaticProps``getInitialProps`などのデータフェッチメソッドを再度実行せずに、URLを変更できます。

状態を失うことなく、`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 })

これは新しいページであるため、シャロールーティングを要求したとしても、現在のページがアンロードされ、新しいページがロードされ、データフェッチが待機されます。

シャロールーティングをミドルウェアと併用する場合、ミドルウェアを使用しない場合のように、新しいページが現在のページと一致することが保証されません。これは、ミドルウェアが動的に書き換えを行うことができ、シャローでスキップされるデータフェッチなしではクライアント側で検証できないためです。そのため、シャロールートの変更は常にシャローとして扱われる必要があります。