Lang x Lang

Linking and Navigating

Next.js 内での routes 間を移動するための 4 つの方法があります:

このページでは、これらの options の使用方法を紹介し、ナビゲーションの動作についてより深く掘り下げます。

<Link>は、プリフェッチと client サイドのナビゲーションを提供するため、HTML の<a>タグを拡張する組み込みの component です。これは、Next.js 内の routes 間を移動するための主要で推奨される方法です。

それを next/link からインポートして使用し、href プロップを component に渡すことができます。

app/page.tsx
import Link from 'next/link'

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

export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>
}

他にも <Link> に渡すことができるオプショナルの props があります。詳しくは API reference をご覧ください。

Examples

Dynamic セグメントへのリンク

dynamic segments にリンクする際、template literals and interpolation を使用してリンクのリストを生成することができます。たとえば、ブログ投稿のリストを生成するには:

app/blog/PostList.js
import Link from 'next/link'

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

アクティブリンクの確認

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

app/components/links.tsx
'use client'

import { usePathname } from 'next/navigation'
import Link from 'next/link'

export function Links() {
  const pathname = usePathname()

  return (
    <nav>
      <ul>
        <li>
          <Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
            Home
          </Link>
        </li>
        <li>
          <Link
            className={`link ${pathname === '/about' ? 'active' : ''}`}
            href="/about"
          >
            About
          </Link>
        </li>
      </ul>
    </nav>
  )
}
app/components/links.js
'use client'

import { usePathname } from 'next/navigation'
import Link from 'next/link'

export function Links() {
  const pathname = usePathname()

  return (
    <nav>
      <ul>
        <li>
          <Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
            Home
          </Link>
        </li>
        <li>
          <Link
            className={`link ${pathname === '/about' ? 'active' : ''}`}
            href="/about"
          >
            About
          </Link>
        </li>
      </ul>
    </nav>
  )
}

idまで Scroll する

Next.js App Router の default の振る舞いは、新しい route のトップへ scroll するか、または前進と戻るナビゲーションの scroll 位置を維持します。

特定の id まで scroll したい場合、# ハッシュの link を URL に追加することができます。または、ハッシュの link を href プロパティに渡すだけでも可能です。これは、<Link><a> 要素にレンダリングされるからです。

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

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

scroll 復元の無効化

default の Next.js App Router の振る舞いは、新しい route の一番上へ scroll するか、後方や前方のナビゲーションで scroll 位置を維持します。この振る舞いを無効にしたい場合は、scroll={false}<Link> component に、または scroll: falserouter.push() または router.replace() へ渡すことができます。

// next/link
<Link href="/dashboard" scroll={false}>
  Dashboard
</Link>
// useRouter
import { useRouter } from "next/navigation";

const router = useRouter();

router.push("/dashboard", { scroll: false });

useRouter() hook

useRouter hook を使用すると、Client Components からプログラムで routes を変更することができます。

app/page.js
'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
  const router = useRouter()

  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}

useRouter Method の完全なリストについては、API reference をご覧ください。

おすすめ: useRouter を使用する特別な要件がある場合を除き、routes 間を移動するために <Link> component を使用してください。

redirect function

Server Components については、代わりに redirect 関数を使用してください。

app/team/[id]/page.tsx
import { redirect } from 'next/navigation'

async function fetchTeam(id: string) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({ params }: { params: { id: string } }) {
  const team = await fetchTeam(params.id)
  if (!team) {
    redirect('/login')
  }

  // ...
}
app/team/[id]/page.js
import { redirect } from 'next/navigation'

async function fetchTeam(id) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({ params }) {
  const team = await fetchTeam(params.id)
  if (!team) {
    redirect('/login')
  }

  // ...
}

Good to know:

  • redirect は default では 307(一時的な Redirect)ステータスコードを返します。Server Action で使用すると、303(See Other)を返し、これは POST request の結果として成功ページに Redirect するために一般的に使用されます。
  • redirect は内部で error をスローするので、try/catchブロックの外で呼び出すべきです。
  • redirect はレンダリングのプロセス中に Client Components で呼び出すことができますが、イベントハンドラーでは呼び出せません。代わりに、useRouter hook を使用できます。
  • redirect は絶対 URL も受け入れ、外部リンクに redirect するために使用することができます。
  • もし render の過程の前に redirect したい場合は、next.config.js または Middleware を使用してください。

詳細については、redirect API referenceをご覧ください。

Using the native History API

Next.js は、ページをリロードせずにブラウザの履歴 stack を更新するためのネイティブな window.history.pushState window.history.replaceState Method を使用することを許可します。

pushStateおよびreplaceStateの呼び出しは、Next.js Router と統合され、usePathnameuseSearchParams との同期を可能にします。

window.history.pushState

それを使用して、ブラウザの履歴 stack に新しいエントリを追加します。ユーザーは以前の状態に戻ることができます。例えば、製品のリストを並べ替えるために:

.tsx
"use client";

import { useSearchParams } from "next/navigation";

export default function SortProducts() {
  const searchParams = useSearchParams();

  function updateSorting(sortOrder: string) {
    const params = new URLSearchParams(searchParams.toString());
    params.set("sort", sortOrder);
    window.history.pushState(null, "", `?${params.toString()}`);
  }

  return (
    <>
      <button onClick={() => updateSorting("asc")}>Sort Ascending</button>
      <button onClick={() => updateSorting("desc")}>Sort Descending</button>
    </>
  );
}
.jsx
"use client";

import { useSearchParams } from "next/navigation";

export default function SortProducts() {
  const searchParams = useSearchParams();

  function updateSorting(sortOrder) {
    const params = new URLSearchParams(searchParams.toString());
    params.set("sort", sortOrder);
    window.history.pushState(null, "", `?${params.toString()}`);
  }

  return (
    <>
      <button onClick={() => updateSorting("asc")}>Sort Ascending</button>
      <button onClick={() => updateSorting("desc")}>Sort Descending</button>
    </>
  );
}

window.history.replaceState

それを使用してブラウザの履歴の stack 上の現在のエントリーを replace します。ユーザーは前の状態に戻ることができません。例えば、アプリケーションの locale を切り替えるには:

"use client";

import { usePathname } from "next/navigation";

export function LocaleSwitcher() {
  const pathname = usePathname();

  function switchLocale(locale: string) {
    // e.g. '/en/about' or '/fr/contact'
    const newPath = `/${locale}${pathname}`;
    window.history.replaceState(null, "", newPath);
  }

  return (
    <>
      <button onClick={() => switchLocale("en")}>English</button>
      <button onClick={() => switchLocale("fr")}>French</button>
    </>
  );
}
"use client";

import { usePathname } from "next/navigation";

export function LocaleSwitcher() {
  const pathname = usePathname();

  function switchLocale(locale) {
    // e.g. '/en/about' or '/fr/contact'
    const newPath = `/${locale}${pathname}`;
    window.history.replaceState(null, "", newPath);
  }

  return (
    <>
      <button onClick={() => switchLocale("en")}>English</button>
      <button onClick={() => switchLocale("fr")}>French</button>
    </>
  );
}

How Routing and Navigation Works

App Router は、ルーティングとナビゲーションにハイブリッドアプローチを使用します。 server 上では、アプリケーションのコードが route セグメントで自動的に code -split されます。そして、 client 上では、 Next.js が route セグメントを prefetchesおよび caches します。つまり、ユーザーが新しい route に移動するとき、ブラウザはページを再ロードせず、変更される route のセグメントだけが再 rendering されます - ナビゲーション体験とパフォーマンスが向上します。

1. Code の分割

Code スプリッティングにより、アプリケーションの code を小さなバンドルに分割し、ブラウザでダウンロードして実行できます。これにより、各 request で転送されるデータ量と実行時間が削減され、パフォーマンスが向上します。

Server Components は、アプリケーションの code が route セグメントごとに自動的にコード分割されることを可能にします。これは、現在の route に必要な code のみがナビゲーション時にロードされることを意味します。

2. プリフェッチング

Prefetching は、ユーザーが訪れる前にバックグラウンドで route を preload する方法です。

Next.js では、routes がプリフェッチされる方法は 2 つあります:

  • <Link> component: Routes は、ユーザーの viewport に表示されると自動的にプリフェッチされます。プリフェッチは、ページが最初に読み込まれたときや scrolls によって表示されるときに行われます。
  • router.prefetch(): useRouter hook は、routes のプリフェッチをプログラムで行うために使用できます。

<Link>のプリフェッチ動作は静的ルートと dynamic routes では異なります。

  • Static Routes: prefetchは default でtrueに設定されています。完全な route が事前に取得されキャッシュされます。
  • Dynamic Routes: prefetch を default から自動に設定します。共有された layout、レンダリングされた Component の tree の下部から最初の loading.jsファイルまでが事前に取得され、30sの間キャッシュされます。これにより、全体的な dynamic route の取得コストが削減され、ユーザーにより視覚的なフィードバックを提供するための、即座に loading 状態を表示することができます。

prefetch プロップを false に設定することで、プリフェッチングを無効にすることができます。

詳細は <Link> API reference をご覧ください。

Good to know:

  • プリフェッチングは development では有効になっておらず、production でのみ有効です。

3. キャッシング

Next.js には、Router Cache と呼ばれるメモリ内 Client 側の cacheがあります。ユーザーが app を回覧するとき、prefetched された route セグメントと訪れた routes が cache に保存されます。React Server Component のペイロードも同様です。

これは、ナビゲーションにおいて、新たに request を server に送る代わりに、 cache が可能な限り再利用されることを意味します - number のリクエストとデータ転送量を削減することでパフォーマンスが向上します。

Router Cache の動作と設定方法について詳しく学びましょう。

4. 部分的なレンダリング

部分的なレンダリングとは、ナビゲーションで再レンダリングされる route セグメントのみが client で再レンダリングされ、共有セグメントは保持されるという意味です。

例えば、二つの routes、/dashboard/settings/dashboard/analyticsをナビゲートする場合、settingsanalyticsのページがレンダリングされ、共有のdashboard layout が保持されます。

How partial rendering works

部分的なレンダリングがなければ、各ナビゲーションにより全ページが client 上で再レンダリングされます。変更があるセグメントだけをレンダリングすることで、転送されるデータ量と実行時間を減らし、パフォーマンスを向上させることができます。

5. ソフトナビゲーション

ブラウザはページ間を移動する際に "hard navigation" を実行します。 Next.js App Router はページ間の "soft navigation" を可能にし、変更された route セグメントのみが再レンダリング(部分レンダリング)されることを保証します。これにより、ナビゲーション中に client React の状態が維持されます。

6. バックとフォワードナビゲーション

default として、Next.js は、後方および前方のナビゲーションに対して scroll ポジションを保持し、Router Cacheの中で route セグメントを再利用します。

7. pages/app/ の間でのルーティング

pages/からapp/へと段階的に移行する際には、 Next.js router が自動的に両者の間でのハードなナビゲーションを処理します。pages/からapp/への遷移を検出するためには、 app routes の確率的なチェックを活用した client router フィルタがあり、これがたまに false の陽性反応を引き起こすことがあります。 default では、このような事例は非常に稀であるはずです。なぜなら、私たちは false の陽性率を 0.01%に設定しているからです。この確率はnext.config.jsexperimental.clientRouterFilterAllowedRateオプションを通じてカスタマイズすることができます。 false の陽性率を下げると、生成されるフィルタの size が client バンドル内で増加することを覚えておくことが重要です。

あるいは、この処理を完全に無効にし、pages/app/間のルーティングを手動で管理することを選好する場合、next.config.jsexperimental.clientRouterFilterを false に設定できます。この機能が無効になると、パージにある任意の dynamic routes が app routes と重複している場合、default では適切に遷移することができません。

当社サイトでは、Cookie を使用しています。各規約をご確認の上ご利用ください:
Cookie Policy, Privacy Policy および Terms of Use