Sponsor
ChatHubChatHub Use GPT-4, Gemini, Claude 3.5 and more chatbots side-by-side
ここをクリック
Menu

リンクとナビゲーション

Next.jsのルーターは、シングルページアプリケーションと同様に、ページ間のクライアントサイドルート遷移を可能にします。

クライアントサイドルート遷移を行うために、Linkという名前のReactコンポーネントが提供されています。

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

上記の例では、複数のリンクを使用しています。それぞれのリンクは、既知のページにパス(href)をマッピングしています:

  • /pages/index.js
  • /aboutpages/about.js
  • /blog/hello-worldpages/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オブジェクトを使用しています:

  • pathnamepagesディレクトリ内のページ名です。この場合は/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')}>
      詳細を読むにはここをクリック
    </button>
  )
}

シャローRouting

シャローRoutingにより、データフェッチメソッドを再実行せずにURLを変更できます。これにはgetServerSidePropsgetStaticPropsgetInitialPropsが含まれます。

useRouterまたはwithRouterによって追加されたrouterオブジェクトを介して、状態を失うことなく、更新されたpathnamequeryを受け取ります。

シャローRoutingを有効にするには、shallowオプションをtrueに設定します。以下の例を考えてみましょう:

import { useEffect } from 'react'
import { useRouter } from 'next/router'
 
// 現在のURLは'/'
function Page() {
  const router = useRouter()
 
  useEffect(() => {
    // 最初のレンダリング後に常にナビゲーションを行う
    router.push('/?counter=10', undefined, { shallow: true })
  }, [])
 
  useEffect(() => {
    // カウンターが変更された!
  }, [router.query.counter])
}
 
export default Page

URLは/?counter=10に更新され、ページは置き換えられず、ルートの状態のみが変更されます。

また、以下のようにcomponentDidUpdateを介してURLの変更を監視することもできます:

componentDidUpdate(prevProps) {
  const { pathname, query } = this.props.router
  // 無限ループを避けるために、プロップが変更されたことを確認
  if (query.counter !== prevProps.router.query.counter) {
    // 新しいクエリに基づいてデータをフェッチ
  }
}

注意点

シャローRoutingのみが、現在のページのURL変更で機能します。例えば、pages/about.jsという別のページがあり、以下を実行するとします:

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

これは新しいページであるため、現在のページをアンロードし、新しいページをロードし、シャローRoutingを要求したにもかかわらず、データフェッチを待機します。

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