🔗

ゼロから学ぶ React, Next.js⑫【Learn Next.js】Chapter5

2024/05/25に公開

【Chapter5】 ページ間のナビゲーション

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

この章で扱うトピック

  • 🔗 next/linkコンポーネントの使い方
  • 💭 usePathname()フックでアクティブなリンクを表示する方法
  • ↗️ Next.jsでのナビゲーションの仕組み

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

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

わかりましたか?

ページを移動するたびにフルページリフレッシュが発生しています!


<Link>コンポーネント

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="...">を使用します。

変更を保存し、localhostで動作するかどうかを確認してください。フルリフレッシュが発生することなく、ページ間を移動できるようになったはずです。アプリケーションの一部はサーバーでレンダリングされますが、フルページリフレッシュは発生せず、Webアプリのように感じられます。なぜでしょうか?

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

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

ルートごとにコードを分割することは、ページが分離されることを意味します。特定のページでエラーが発生しても、アプリケーションの残りの部分は引き続き機能します。

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

ナビゲーションの仕組みの詳細については、こちら
をご覧ください。

クイズの時間です!
知識をテストし、学んだことを確認しましょう。

本番環境でブラウザのビューポートに<Link>コンポーネントが表示されたとき、Next.jsは何をしますか?

A. 追加のCSSをダウンロードする
B. 画像をプリロードする
C. リンク先のルートのコードをプリフェッチする
D. リンク先のルートの遅延ロードを有効にする

解答

C. リンク先のルートのコードをプリフェッチする
Next.jsはリンク先のコードをバックグラウンドで自動的にプリフェッチします。ユーザーがリンクをクリックするころには、リンク先ページのコードはすでにバックグラウンドで読み込まれています!


パターン:アクティブなリンクを表示する

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

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

/app/ui/dashboard/nav-links.tsx
+'use client';
 
import {
  UserGroupIcon,
  HomeIcon,
  InboxIcon,
} 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();
  // ...
}


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>
        );
      })}
    </>
  );
 }

保存してlocalhostを確認してください。アクティブなリンクが青色で強調表示されるようになったはずです。

アクティブなリンクが青色で強調表示されるダッシュボード


次の章

https://zenn.dev/gunjo/articles/9ce321728a7d81

Discussion