前回
Next.jsのチュートリアルをやってみる【レイアウトとページ編】はじめに
前回はダッシュボードのレイアウトとページを作成しました。今回はユーザーがダッシュボードのルート間をナビゲートできるようにリンクを追加していきます。
ナビゲーションを最適化する理由
ページ間のリンクにはHTML要素である<a>
タグを使用することができます。すでにサイドバーのリンクには<a>
タグを使用していますので、実際にクリックして移動してみましょう。
クリックすると全ページが更新されていることが分かります。
<Link> コンポーネント
Next.jsでは<Link />
コンポーネントを使用して、アプリケーション内のページ間をリンクすることができます。<Link>
を使用すると、JavaScriptでクライアントサイドナビゲーションを行うことができます。
<Link />
コンポーネントを使用するには、/app/ui/dashboard/nav-links.tsx
を開き、next/link
からLink
コンポーネントをインポートします。
それでは、ナビゲーションで使用されている<a>
タグを<Link>
コンポーネントに置き換えてみましょう。
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はリンク先のリートのコードをバックグラウンドで自動的にプリフェッチします。ユーザーがリンクをクリックするころには、リンク先のページのコードはすでにバックグラウンドで読み込まれているのです。
さらに詳しく知りたい方は公式ドキュメントの「Linking and Navigating」のHow Routing and Navigation Works」セクションを確認してください。
問題1
本番環境で、コンポーネントがブラウザのビューポートに表示されたとき、Next.jsは何をしますか?
- 追加CSSのダウンロード
- 画像のプリロード
- リンクされたルートのコードをプリフェッチする。
- リンクされたルートの遅延ロードを有効にする
3. リンクされたルートのコードをプリフェッチする。
Next.jsはリンク先のコードをバックグラウンドで自動的にプリフェッチします。 ユーザーがリンクをクリックするころには、リンク先ページのコードはすでにバックグラウンドで読み込まれています。
パターン:アクティブリンクの表示
一般的なUIパターンは、ユーザーが現在どのページにいるのかを示すために、アクティブなリンクを表示するというパターンです。このパターンを追加するにはURLからユーザーの現在のパスを取得する必要があります。Next.jsにはusePathname()
というフックが用意されているので、それを使ってパスをチェックしこのパターンを実装することができます。
usePathname()
はフックなので、nav-links.tsx
をクライアント・コンポーネントにする必要があります。ファイルの先頭に'use client'
ディレクティブを追加し、next/navigation
からusePathname()
をインポートします。
コードを以下のように変更しましょう。
'use client';
import {
UserGroupIcon,
HomeIcon,
InboxIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
// ...
続いて、<NavLinks />
コンポーネント内のpathname
という変数にパスを代入します。
export default function NavLinks() {
const pathname = usePathname();
// ...
}
CSS編で紹介したclsx
ライブラリを使用すれば、リンクがアクティブなときに条件付きでクラス名を運用できます。link.href
がパス名と一致するとき、リンクは青いテキストと水色の背景で表示されるようになります。
最終的にはこの用意なりました。
'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>
);
})}
</>
);
}
サーバーが起動されていることを確認し、改めて確認してみましょう。
まとめ
- ページ間の移動で使用するナビゲーションは
<a>
タグと<Link>
コンポーネントを使用することが可能<a>
タグは通常のページ遷移となる。<Link >
コンポーネントはクライアントサイド・ナビゲーションとなる。ページすべてではなく、部分的な遷移となる。<Link>
コンポーネントはルートセグメントごとにアプリケーションを分割するため、一部にエラーが起きても残りの部分は動作し続ける。- 本番環境で
<Link>
コンポーネントを使用すると、リンク先のルートをプリフェッチするため、ユーザーがリンクをクリックするころには、すでにリンク先のコードが読み込まれている。