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: false を router.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 と統合され、usePathname と useSearchParams との同期を可能にします。

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をナビゲートする場合、settingsとanalyticsのページがレンダリングされ、共有の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.jsのexperimental.clientRouterFilterAllowedRateオプションを通じてカスタマイズすることができます。 false の陽性率を下げると、生成されるフィルタの size が client バンドル内で増加することを覚えておくことが重要です。

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

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