ページ間のナビゲーション

前の章では、ダッシュボードのレイアウトとページを作成しました。ここでは、ユーザーがダッシュボードのルート間を移動できるようにリンクを追加しましょう。

ナビゲーションを最適化する理由

ページ間をリンクする場合、従来は <a> HTML要素を使用していました。現在、サイドバーのリンクは <a> 要素を使用していますが、ブラウザでホーム、請求書、顧客ページ間を移動すると何が起こるか確認してください。

気づきましたか?

各ページナビゲーションでページ全体がリフレッシュされます!

Next.jsでは、アプリケーション内のページ間をリンクするために <Link /> コンポーネントを使用できます。<Link> を使用すると、JavaScriptによるクライアントサイドナビゲーションが可能になります。

<Link /> コンポーネントを使用するには、/app/ui/dashboard/nav-links.tsx を開き、next/link から Link コンポーネントをインポートします。次に、<a> タグを <Link> に置き換えます:

/app/ui/dashboard/nav-links.tsx
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
 
// ...
 
export default function NavLinks() {
  return (
    <>
      {links.map((link) => {
        const LinkIcon = link.icon;
        return (
          <Link
            key={link.name}
            href={link.href}
            className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
          >
            <LinkIcon className="w-6" />
            <p className="hidden md:block">{link.name}</p>
          </Link>
        );
      })}
    </>
  );
}

ご覧の通り、Link コンポーネントは <a> タグの使用と似ていますが、<a href="…"> の代わりに <Link href="…"> を使用します。

変更を保存し、ローカルホストで動作を確認してください。これでページ間を移動してもページ全体がリフレッシュされなくなります。アプリケーションの一部はサーバーでレンダリングされますが、ページ全体のリフレッシュがないため、ネイティブウェブアプリのような感覚になります。なぜでしょうか?

自動コード分割とプリフェッチ

ナビゲーション体験を向上させるため、Next.jsはルートセグメントごとにアプリケーションを自動的にコード分割します。これは従来のReact SPAとは異なり、ブラウザが初期ページロード時にすべてのアプリケーションコードを読み込む必要がありません。

ルートごとにコードを分割することで、ページが独立します。特定のページでエラーが発生しても、アプリケーションの他の部分は引き続き動作します。また、ブラウザが解析するコード量も少なくなるため、アプリケーションが高速になります。

さらに、本番環境では、<Link> コンポーネントがブラウザのビューポートに表示されると、Next.jsは自動的にリンクされたルートのコードをバックグラウンドでプリフェッチします。ユーザーがリンクをクリックする時点では、すでに移動先ページのコードがバックグラウンドで読み込まれているため、ページ遷移がほぼ瞬時に行われます!

ナビゲーションの仕組みについて詳しく学びましょう。

パターン: アクティブなリンクの表示

一般的なUIパターンとして、ユーザーが現在どのページにいるかを示すためにアクティブなリンクを表示することがあります。これを行うには、URLからユーザーの現在のパスを取得する必要があります。Next.jsは usePathname() というフックを提供しており、これを使用してパスを確認し、このパターンを実装できます。

usePathname() はReactフックであるため、nav-links.tsx をクライアントコンポーネントに変換する必要があります。ファイルの先頭にReactの "use client" ディレクティブを追加し、next/navigation から usePathname() をインポートします:

/app/ui/dashboard/nav-links.tsx
'use client';
 
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
 
// ...

次に、<NavLinks /> コンポーネント内で pathname という変数にパスを割り当てます:

/app/ui/dashboard/nav-links.tsx
export default function NavLinks() {
  const pathname = usePathname();
  // ...
}

: nav-links.tsx はNext.jsにとって特別なファイルではありません - 任意の名前を付けることができます。名前を変更する場合は、インポート文を適宜更新してください。

CSSスタイリングの章で紹介した clsx ライブラリを使用して、リンクがアクティブな場合にクラス名を条件付きで適用できます。link.hrefpathname と一致する場合、リンクは青いテキストと薄い青の背景で表示されます。

以下は nav-links.tsx の最終的なコードです:

/app/ui/dashboard/nav-links.tsx
'use client';
 
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import clsx from 'clsx';
 
// ...
 
export default function NavLinks() {
  const pathname = usePathname();
 
  return (
    <>
      {links.map((link) => {
        const LinkIcon = link.icon;
        return (
          <Link
            key={link.name}
            href={link.href}
            className={clsx(
              'flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3',
              {
                'bg-sky-100 text-blue-600': pathname === link.href,
              },
            )}
          >
            <LinkIcon className="w-6" />
            <p className="hidden md:block">{link.name}</p>
          </Link>
        );
      })}
    </>
  );
}

変更を保存し、ローカルホストを確認してください。これでアクティブなリンクが青でハイライト表示されるようになります。