⚡️ 【Next.js入門】Linkコンポーネントとaタグの違いを完全理解！

# Next.jsの`<Link>`コンポーネントと`<a>`タグの違い

私は`Next.js`と`tailwindcss`を使用し、フロントエンド開発を行っている初心者です。`Next.js`を使用してWebアプリケーションを構築している中で、`<Link>`コンポーネントと`<a>`タグの使い分けに疑問を感じました。どちらもリンクを生成するタグですが、`Next.js`の公式ドキュメントを読むと、`<Link>`コンポーネントを使用することが推奨されています。
色々と調べた結果、それぞれの特徴と適切な使い分けについて理解できましたので、今回はその知見を共有させていただきます。

## 目次

- [はじめに](#はじめに)
- [基本的な使用例](#基本的な使用例)
- [内部処理の仕組みと技術的背景](#内部処理の仕組みと技術的背景)
- [アクセシビリティのベストプラクティス](#アクセシビリティのベストプラクティス)
- [トラブルシューティング](#トラブルシューティング)
- [発展的な使用方法](#発展的な使用方法)
- [まとめ](#まとめ)

## はじめに

`Next.js`は、`React`をベースにした非常に人気のあるフルスタックフレームワークで、サーバーサイドレンダリング（SSR）や静的サイト生成（SSG）といった強力な機能を提供し、高速でパフォーマンスの高いWebアプリケーションを開発できます。
その中でも、ページ間のナビゲーションは最も基本的かつ重要な機能の一つです。従来の`HTML`開発では`<a>`タグを使用してきましたが、`Next.js`では専用の`<Link>`コンポーネントが提供されています。
しかし、`<Link>`コンポーネントは、`Next.js`アプリケーション内のページ遷移に特化して設計されており、外部サイトへの遷移には適してません。今回は、`<Link>`コンポーネントと`<a>`タグの使い分けについて、この二つの違いを理解し、適切な使い分けができるように解説します。
    

## 基本的な使用例

### `<Link>`コンポーネントの基本的な使用方法

```tsx
import Link from 'next/link'

// ナビゲーション用のコンポーネント
function Navigation() {
  return (
    // ナビゲーション
    <nav>
      {/* "About"ページへのリンク */}
      <Link href="/about">About</Link>
      {/* "Blog"ページへのリンク */}
      <Link href="/blog">Blog</Link>
    </nav>
  )
}
```

`<Link>`コンポーネントは、`Next.js`アプリケーション**内**での画面遷移に使用します。
特徴として以下があります。
- クライアントサイドでの画面遷移が可能（ページの再読み込みが発生しない）
- プリフェッチ機能によって、リンク先のデータを事前に読み込める
- パフォーマンスが最適化される

### `<a>`タグの基本的な使用方法(`HTML`)

```html
<nav>
  <a href="/about">About</a>
  <a href="/blog">Blog</a>
</nav>
```

`<a>`タグは、主に**外**部サイトへのリンクに使用します。
特徴として以下があります。
- 新しいタブでの表示が可能
- 従来の`HTML`標準の動作
- ページの完全な再読み込みが発生

## 内部処理の仕組みと技術的背景

### `<Link>`コンポーネントの内部処理

- ルーティング処理（Webサイトの各ページへの行き先の管理）
    - `React`のルーターと連携して、URLの変更を検知
    - `JavaScript`を使用してページの履歴を管理
    - ブラウザのURLバーを更新
- データの事前読み込み
    - バックグラウンドでページデータを自動的に読み込み
    - 必要な`JavaScript`ファイルを事前に準備
    - ユーザーがクリックする前からデータを用意
- 部分的な更新
    - ページ全体ではなく、変更が必要な部分のみを更新
    - アプリケーションの状態を保持
    - アニメーションなどの視覚効果を維持

:::note info
#### `<Link>`コンポーネントの主要な`props`
`<Link>`コンポーネントで使用できる主要な`props`をまとめました。
これらの`props`を使うことで、リンクの挙動をカスタマイズできます。
蛇足かなと考え、アコーディオンにしております。
内容は以下の通りです。
- 6つのプロパティを表形式で紹介
- 各プロパティの使い方を示す簡潔なコード例

確認したい場合は下記をクリックしてください。
:::


<details><summary> Linkコンポーネントの主要なpropsをクリックで確認</summary>


| props名 | 型 | デフォルト値 | 説明 |
|---------|-----|-------------|------|
| href | string | 必須 | リンク先のURL（必ず指定する必要があります） |
| as | string | href値 | ブラウザに表示されるURLのカスタマイズ | 
| prefetch | boolean | true | リンク先のページを事前に読み込むかどうか |
| replace | boolean | false | trueの場合、ブラウザの履歴に新しいページを追加せず、現在のページを置き換えます |
| scroll | boolean | true | ページ遷移後に画面上部にスクロールするかどうか |
| shallow | boolean | false | trueの場合、データの再取得なしでURLだけを更新します |

### 使用例

```tsx
// 基本的な使用例
<Link href="/about">About</Link>

// 動的なページのURLを、実際の商品IDで分かりやすく表示する
<Link href="/product/[id]" as="/product/123">商品123</Link>

// 事前読み込みを無効にする場合
<Link href="/blog" prefetch={false}>Blog</Link>

// 履歴を残さずにページを遷移する場合
<Link href="/settings" replace>Settings</Link>

// ページ遷移時のスクロールを無効にする場合
<Link href="/articles" scroll={false}>Articles</Link>

// URLのみを更新する場合（データの再取得なし）
<Link href="/dashboard" shallow>Dashboard</Link>
```

</details>

#### 詳細

`<Link>`コンポーネントは、`Next.js`のライブラリであるため、通常の`React`コンポーネントとして働きます。このコンポーネントの主な役割は、ページ間の移動をクライアントサイドで行うことにあります。

ブラウザはページ全体をリロードするのではなく、`Next.js`がページに必要な部分だけを書き換えます。
具体的には、`React`のコンポーネントツリーを比較し、変更があった部分だけをDOM（Webページの構造を表すもの）に反映させます。
これにより、ページ全体の再読み込みなしに、スムーズにページ遷移が実現します。

`prefetch`属性が有効な場合、`Next.js`はリンク先のページの`JavaScript`コードを事前に読み込んでおきます。
これにより、ユーザーがリンクをクリックした際に、ページがほぼ瞬時に表示されるため、ユーザーエクスペリエンスが向上します。

このように、`<Link>`コンポーネントはクライアントサイドでの遷移を実現することで、`<a>`タグよりも高速でスムーズなページ遷移を提供します。 `Next.js`のルーティング機能と`React`の仮想DOM（実際の画面とは別に用意された仮想的な画面データ）を利用することで、ページ全体のリロードなしに、必要な部分だけを書き換えることができます。

:::note info
##### `Next.js 13`以降の`App Router`と`Pages Router`での実装の違い
`<Link>`コンポーネントの基本的な使い方は両方のルーティングシステムで同じですが、念のため、`App Router`と`Pages Router`の主な違いを簡潔にまとめておきます。
確認したい場合は下記をクリックしてください
:::

<details><summary>App RouterとPages Routerでの実装の違いをクリックで確認</summary>
`Next.js 13`から導入された`App Router`は、従来の`Pages Router`と比べて、ルーティングの仕組みが大きく変わりました。

### フォルダ構成
- `App Router`: `app`ディレクトリで管理
- `Pages Router`: `pages`ディレクトリで管理
            
### クライアントサイドコンポーネント
- `App Router`:  `'use client'`の宣言が**必要**（サーバーコンポーネントがデフォルトのため）
- `Pages Router`:  `'use client'`の宣言が**不要**（すべてクライアントコンポーネントのため）

### ルーティング
- `App Router`  
    - `app`ディレクトリを基にした**フォルダ**構成を反映した自動ルーティング
    - 各ページは`page.tsx`として定義され、ディレクトリ構造でルーティングが決定
- `Pages Router`
    - `pages`ディレクトリを基にした**ファイル**ベースのルーティング
    - `index.tsx`がトップページとなり、ファイル名でルーティングが決定

</details>


### `<a>`タグの内部処理

- ページ遷移処理
    - ブラウザの標準的なページ遷移を実行
    - 新しい`HTML`ページを完全に読み込み
    - `JavaScript`の状態をリセット
- リソースの読み込み
    - `CSS`や`JavaScript`ファイルを新たに読み込み
    - 画像などのメディアファイルも再度ダウンロード
    - キャッシュがある場合はそれを使用
- ブラウザの動作
    - 戻る・進むボタンの標準的な動作を提供
    - ブックマーク機能との連携
    - 右クリックメニューなどの標準機能を利用可能

#### 詳細

`<a>`タグは`HTML`の標準タグであり、ページ内の他の場所に移動する、または外部リソースにアクセスするために使用されます。

`<a>`タグはページ全体をリロードするため、画面が一度白くなってから新しいページが表示されることになります。 
また、サーバーにリクエストを送るたびに、毎回`HTML`や`CSS`、`JavaScript`などを再度読み込む必要があります。
これは、特に複雑なWebアプリケーションでは、ユーザーエクスペリエンスの低下やパフォーマンスの問題につながる可能性があります。

#### `<a>`タグのSEOでの役割について

`<a>`タグはSEO（検索エンジン最適化）において非常に重要な役割を持っています。SEOにおける効果は、以下の要素を意識することで向上させることができます。

##### アンカーテキスト
```html
<a href="https://example.com">次世代のテクノロジーに関する記事</a>
```
アンカーテキスト（リンクのテキスト部分）が何に関するリンクかを語る言葉であることが重要です。検索エンジンはアンカーテキストを通じてリンク先の内容を理解し、ランキングに影響を与えます。

##### リンク先の関連性
`<a>`タグでリンクを貼る際、リンク先のコンテンツが自サイトの内容と関連性が高いほどSEO効果が期待できます。関連性の高いリンクは、訪問者の体験を向上させ、滞在時間の増加につながることもあります。

### 技術的な違いのポイント

#### レンダリング方式

`<Link>`: クライアントサイドレンダリングによる部分更新
`<a>`: サーバーサイドでの完全なページ再読み込み

#### パフォーマンス

`<Link>`: 高速な遷移とリソースの効率的な管理
`<a>`: 標準的なページ読み込みによる追加の待ち時間
#### 使用シーン

`<Link>`: `Next.js`アプリケーション**内**の画面遷移
`<a>`: **外**部サイトへのリンクやSEO最適化が必要な場合

## アクセシビリティのベストプラクティス

Webアクセシビリティは、すべての人が問題なくWebページを利用できるようにするための重要な考慮事項です。中でも、`aria-label`属性は、視覚障害のあるユーザーがスクリーンリーダーを使用してサイトを操作する際に役立ちます。

### `aria-label`の適切な使用
```tsx
// ❌ 不適切な実装例
<Link href="/home">
  <img src="/home-icon.png" />
</Link>

// ✅ 正しい実装例
<Link 
  href="/home"
  aria-label="ホームページへ戻る" // スクリーンリーダーが読み上げるテキスト
>
  <img 
    src="/home-icon.png"
    alt="ホームアイコン" // 画像の説明文
  />
</Link>
```

### リンクの目的を明確にする
```
// ❌ 不適切な実装例
<Link href="/blog/1">
  こちら
</Link>

// ✅ 正しい実装例
<Link href="/blog/1">
  ブログ記事「Next.jsの基礎」を読む
</Link>
```

## トラブルシューティング

### 内部ページへのリンク

```tsx
// ❌ 間違った実装例
<nav>
  <a href="/about">About</a>  
  <a href="/blog">Blog</a>
</nav>

// ✅ 正しい実装例
<nav>
  <Link href="/about">About</Link>
  <Link href="/blog">Blog</Link>
</nav>
```

`Next.js`のアプリケーション内で内部ページに`<a>`タグで遷移しようとすると、ブラウザのリロードが発生し、せっかくの`Next.js`の高速なページ遷移の恩恵を受けることができません。
`<Link>`コンポーネントを使用することで、ブラウザのリロードが発生しないため、ユーザーエクスペリエンスが向上します。

### 外部サイトへのリンク

```tsx
// ❌ 間違った実装例
<Link href="https://external-site.com">
  外部サイトへ
</Link>

// ✅ 正しい実装例
<a href="https://external-site.com" target="_blank" rel="noopener noreferrer">
  外部サイトへ
</a>
```

外部サイトへのリンクには、`<a>`タグを使用する必要があります。
また、新しいタブで開く場合は、セキュリティ対策として以下の属性を追加することが推奨されています。

- `target="_blank"`: リンクを新しいタブで開く
- `rel="noopener noreferrer"`: セキュリティ対策として必要
  - noopener: 新しく開いたページから元のページを参照できないようにする
  - noreferrer: リファラー情報（どのページから来たか）を送信しない

### エラーの適切な処理(リンク先のページやコンテンツが変更された場合)

`Next.js 14`では`App Router`を使用することで、エラーページを簡単に実装できます。
以下の2つのファイルを作成するだけで、自動的にエラーハンドリングが行われます。

1. `error.tsx`: 予期せぬエラーが発生した場合の画面
2. `not-found.tsx`: ページが見つからない場合(404エラー)の画面

```tsx
// app/error.tsx
'use client' // エラーコンポーネントはクライアントコンポーネントである必要があります

// エラーページの実装例
export default function Error({
  error,  // エラーの詳細情報が入るオブジェクト
  reset,  // ページを再読み込みする関数
}: {
  // エラー特定用のオプション情報を含むエラーオブジェクト
  // digest:エラーの発生場所を特定し効率的なデバッグを可能にするための識別子
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <div>
      {/* エラーメッセージ */}
      <h1>エラーが発生しました</h1>
      <p>予期せぬエラーが発生しました。お手数ですが、もう一度お試しください。</p>
      
      {/* リトライボタン */}
      <button onClick={() => reset()}>
        もう一度試す
      </button>

      {/* ホームページへの誘導リンク */}
      <Link href="/">
        ホームページへ戻る
      </Link>
    </div>
  )
}

// app/not-found.tsx
// 404エラーページの実装例
export default function NotFound() {
  return (
    <div>
      {/* エラーメッセージ */}
      <h1>ページが見つかりませんでした</h1>
      <p>お探しのページは存在しないか、移動した可能性があります。</p>
      
      {/* ホームページへの誘導リンク */}
      <Link href="/">
        ホームページへ戻る
      </Link>
    </div>
  )
}
```

これらのファイルを配置することで、以下のような場合に自動的に適切なエラー画面が表示されます。

`error.tsx`: システムエラーやデータの取得失敗など、予期せぬエラーが発生した場合
`not-found.tsx`: URLに対応するページが存在しない場合

特に`error.tsx`では`reset`関数が提供されており、これを使用することでユーザーが簡単にページの再読み込みを試すことができます。これは一時的なエラーが発生した場合に特に有用です。

## 発展的な使用方法

### `prefetch`属性の詳細と制御

```tsx
import Link from 'next/link';

function Navigation() {
  return (
    <nav>
      <Link href="/about" prefetch={true}>About</Link>
      <Link href="/blog" prefetch={false}>Blog</Link> 
    </nav>
  );
}
```

`prefetch`属性は、リンク先のページを事前に読み込むかどうかを指定します。
`prefetch={true}`とすると、リンクがブラウザのビューポート内に入った時点で、`Next.js`はリンク先のページをバックグラウンドで読み込み始めます。
これにより、ユーザーがリンクをクリックした際に、ほぼ瞬時にページ遷移が完了し、より快適なユーザーエクスペリエンスを提供できます。
デフォルトでは`prefetch={true}`なので、明示的に`false`を指定しない限り、`prefetch`が有効になります。
`prefetch={false}`を使うと、特定のページは事前読み込みをしないように設定できます。

### 動的ルーティングでの`<Link>`コンポーネントの使用例

`Next.js`では、動的なURL（例: /blog/123や/products/abcのように、URLの一部が変数になるようなもの）を扱う際に、`<Link>`コンポーネントを使うことで、より柔軟なルーティングを実現できます。

```tsx
// 商品一覧ページでの使用例
function ProductList() {
  // 商品データの配列（実際のアプリではAPIから取得することが多い）
  const products = [
    { id: 1, name: "商品A" },
    { id: 2, name: "商品B" },
    { id: 3, name: "商品C" }
  ]

  return (
    <div>
      <h1>商品一覧</h1>
      <ul>
        {products.map((product) => (
          // mapでリストを生成する場合は、必ずkeyを指定
          <li key={product.id}>
            {/* 動的なURLを生成 */}
            <Link href={`/products/${product.id}`}>
              {product.name}を見る
            </Link>
          </li>
        ))}
      </ul>
    </div>
  )
}
```

## まとめ

`Next.js`における`<Link>`と`<a>`タグは、それぞれのユースケースに応じた特有の機能を持っています。`<Link>`コンポーネントはクライアントサイドナビゲーションを可能にし、ページ遷移をスムーズにします。特に、リンク先のページデータを事前にロードしてユーザーエクスペリエンスを向上させるプリフェッチ機能は、動的な`React`アプリケーションにおいて重要な役割を果たします。一方、ベーシックな`<a>`タグは外部サイトへのリンクやSEOの最適化において依然として有効です。

もし記事の内容に間違いがあれば、コメントでご指摘いただけますと幸いです。また、より良い方法や代替手段をご存知の方がいらっしゃいましたら、ぜひ共有していただければと存じます。例えば、特定の条件下での最適なリンク手法や、よりデザインに特化したリンクのスタイリングなど、皆様の知見をお聞かせいただければ嬉しいです。