Linkコンポーネントによる画面遷移

2025-08-12

はじめに

前回までにNext.jsのページコンポーネント作成方法を学びました。今回は、作成したページ間をシームレスに移動するための「Linkコンポーネント」について詳しく解説します。ReactのSPA(シングルページアプリケーション)経験者にとって、Next.jsのナビゲーションはより簡単でパワフルです。

なぜLinkコンポーネントが必要か?

従来のaタグの問題点

通常のHTMLではページ遷移に<a>タグを使用しますが、これには以下の問題があります:

  1. ページ全体のリロードが発生し、パフォーマンスが低下
  2. アプリケーション状態がリセットされてしまう
  3. スムーズな遷移ができない

Linkコンポーネントのメリット

Next.jsのLinkコンポーネントを使用すると:

  1. クライアントサイドナビゲーション(ページ全体のリロードなし)
  2. アプリ状態の保持(Reactの状態が維持される)
  3. 自動的なプリフェッチ(viewport内のリンクを自動で先読み)
  4. 高速なページ遷移

Linkコンポーネントの基本使用法

1. 基本的なインポートと使用

まず、next/linkからLinkコンポーネントをインポートします:

import Link from 'next/link';

function Navigation() {
  return (
    <nav>
      <Link href="/">ホーム</Link>
      <Link href="/about">About</Link>
      <Link href="/products">製品情報</Link>
    </nav>
  );
}

2. スタイルを適用する場合

Linkコンポーネント自体にスタイルは適用できないので、子要素を追加します:

<Link href="/about">
  <a className="nav-link">Aboutページ</a>
</Link>

// Next.js v13以降では以下のように記述
<Link href="/about" className="nav-link">
  Aboutページ
</Link>

3. ボタンとして使用

<Link href="/contact">
  <button className="btn btn-primary">お問い合わせ</button>
</Link>

Linkコンポーネントの詳細な使い方

1. 動的ルートへのリンク

動的ルート([id].jsや[slug].jsなど)にリンクする場合:

<Link href={`/blog/${post.slug}`}>
  <a>{post.title}</a>
</Link>

// またはオブジェクト形式で
<Link href={{
  pathname: '/blog/[slug]',
  query: { slug: post.slug }
}}>
  <a>{post.title}</a>
</Link>

2. URLクエリパラメータの使用

クエリパラメータを付与する場合:

<Link href={{
  pathname: '/search',
  query: { keyword: 'nextjs' }
}}>
  <a>Next.jsで検索</a>
</Link>

3. リンクの挙動をカスタマイズ

replacescrollプロパティで挙動を変更:

<Link href="/" replace scroll={false}>
  <a>ホームに戻る(履歴に残さない、スクロール位置をリセットしない)</a>
</Link>
  • replace: trueにすると、ブラウザの履歴に現在のページを残さない
  • scroll: falseにすると、ページ遷移後トップにスクロールしない

アクティブなリンクのスタイリング

現在のページに対応するリンクにスタイルを適用するには、useRouterフックを使用します:

import { useRouter } from 'next/router';
import Link from 'next/link';

function NavItem({ href, children }) {
  const router = useRouter();
  const isActive = router.pathname === href;

  return (
    <Link href={href}>
      <a className={isActive ? 'active' : ''}>
        {children}
      </a>
    </Link>
  );
}

// 使用例
<NavItem href="/">ホーム</NavItem>
<NavItem href="/about">About</NavItem>

Linkコンポーネントの高度な機能

1. プリフェッチの制御

Next.jsはデフォルトでviewport内のLinkを自動プリフェッチしますが、無効化も可能:

<Link href="/about" prefetch={false}>
  <a>About(プリフェッチしない)</a>
</Link>

2. プログラムによるナビゲーション

useRouterフックでプログラム的にページ遷移:

import { useRouter } from 'next/router';

function LoginButton() {
  const router = useRouter();

  const handleLogin = () => {
    // ログイン処理後にダッシュボードへ遷移
    router.push('/dashboard');
  };

  return (
    <button onClick={handleLogin}>
      ログイン
    </button>
  );
}

3. 遷移イベントの監視

ページ遷移の開始と完了を監視:

import { useEffect } from 'react';
import { useRouter } from 'next/router';

function PageProgress() {
  const router = useRouter();

  useEffect(() => {
    const handleStart = (url) => {
      console.log(`Loading: ${url}`);
      // プログレスバーを表示など
    };

    const handleComplete = (url) => {
      console.log(`Loaded: ${url}`);
      // プログレスバーを非表示など
    };

    router.events.on('routeChangeStart', handleStart);
    router.events.on('routeChangeComplete', handleComplete);

    return () => {
      router.events.off('routeChangeStart', handleStart);
      router.events.off('routeChangeComplete', handleComplete);
    };
  }, []);

  return null;
}

よくある間違いとベストプラクティス

避けるべきパターン

  1. aタグを直接使用しない:
   // 悪い例(ページ全体がリロードされる)
   <a href="/about">About</a>

   // 良い例
   <Link href="/about"><a>About</a></Link>
  1. イベントハンドラをLinkに直接追加しない:
   // 悪い例
   <Link href="/about" onClick={handleClick}>
     <a>About</a>
   </Link>

   // 良い例
   <Link href="/about">
     <a onClick={handleClick}>About</a>
   </Link>

ベストプラクティス

  1. 一貫したリンクスタイル:
  • アプリ全体でリンクのスタイルを統一
  • hoverやfocus状態も考慮
  1. アクセシビリティの確保:
   <Link href="/about">
     <a aria-current={router.pathname === '/about' ? 'page' : undefined}>
       About
     </a>
   </Link>
  1. 重要なナビゲーションはプリフェッチ:
  • 主要なナビゲーションリンクはprefetch={true}(デフォルト)を維持
  • 使用頻度の低いリンクはprefetch={false}

実際の使用例

ナビゲーションバーの実装

import Link from 'next/link';
import { useRouter } from 'next/router';

export default function Navbar() {
  const router = useRouter();

  return (
    <nav className="navbar">
      <div className="logo">
        <Link href="/">
          <a>MyApp</a>
        </Link>
      </div>
      <div className="links">
        <Link href="/">
          <a className={router.pathname === '/' ? 'active' : ''}>ホーム</a>
        </Link>
        <Link href="/about">
          <a className={router.pathname === '/about' ? 'active' : ''}>About</a>
        </Link>
        <Link href="/products">
          <a className={router.pathname === '/products' ? 'active' : ''}>製品</a>
        </Link>
        <Link href="/contact">
          <a className={router.pathname === '/contact' ? 'active' : ''}>お問い合わせ</a>
        </Link>
      </div>
    </nav>
  );
}

ブログ記事一覧の実装

import Link from 'next/link';

export default function PostList({ posts }) {
  return (
    <div className="post-list">
      {posts.map((post) => (
        <article key={post.id} className="post-card">
          <Link href={`/blog/${post.slug}`}>
            <a>
              <h2>{post.title}</h2>
              <p>{post.excerpt}</p>
              <time dateTime={post.date}>{post.date}</time>
            </a>
          </Link>
        </article>
      ))}
    </div>
  );
}

まとめ

Next.jsのLinkコンポーネントは、SPAのようなスムーズなユーザー体験を簡単に実現する強力なツールです。主なポイントは:

  1. 従来の<a>タグの代わりにLinkを使用することでクライアントサイドナビゲーションを実現
  2. 動的ルートやクエリパラメータにも簡単に対応
  3. プリフェッチ機能でパフォーマンスを最適化
  4. useRouterでプログラム的なナビゲーションや状態管理が可能

Next.jsのルーティングシステムを活用すれば、ユーザー体験が向上し、SEOにも有利なアプリケーションを構築できます。次回は、Next.jsの重要な機能である「静的生成(SSG)」について詳しく解説します。

さらに深く学びたい方は、Next.js公式ドキュメントも参照してください:
https://nextjs.org/docs/api-reference/next/link