発行:
更新:

Next.jsのレンダリング

Next.js を学ぶ上で少し難しく、しかし最も重要なのが 「レンダリング(HTMLの生成)」 の仕組みです。
「いつ」「どこで」HTMLが作られるのかを理解すると、Next.js で作れるアプリケーションの幅がぐっと広がります。

レンダリングとは?

React や Next.js におけるレンダリングとは、 コードを元にブラウザが表示できるHTMLを組み立てること を指します。

この「組み立て」を、

  • サーバー でやるのか? ブラウザ (クライアント)でやるのか?
  • ビルド時 に1回だけやるのか? アクセスがある度 に毎回やるのか?

これらを使い分けるのが Next.js の強力な機能です。

主なレンダリング方式

1. Static Site Generation (SSG) / 静的サイト生成

  • タイミング : ビルド時(npm run build をした時)
  • 場所 : サーバー(ビルド環境)
  • 特徴 : あらかじめHTMLファイルを作っておくので、アクセス時の表示が 爆速 です。ブログ記事やドキュメントなど、内容が頻繁に変わらないページに向いています。

2. Server-Side Rendering (SSR) / サーバーサイドレンダリング

  • タイミング : リクエスト時(ユーザーがアクセスした瞬間)
  • 場所 : サーバー
  • 特徴 : アクセスのたびに最新データでHTMLを作ります。SNSのタイムラインやダッシュボードなど、常に最新情報が必要なページに向いています。

3. Client-Side Rendering (CSR)

  • タイミング : ブラウザでJavaScriptが実行された時
  • 場所 : ブラウザ(クライアント)
  • 特徴 : サーバーからは最低限のHTMLだけを送り、ブラウザ側でJavaScriptが画面を組み立てます。ユーザー操作に応じて画面が変わるアプリケーションのような動き(検索画面やフィルター機能など)に向いています。
  • ※ Next.js では、初期表示はサーバーで作るのが基本ですが、use client を使うことでブラウザ側での動的な振る舞いを追加できます。

Next.js (App Router) での使い分け

App Router では、 fetch関数 の書き方ひとつで、SSGやSSRを切り替えることができます。

⚠️ 重要: 最新仕様での変更点

近年、fetch 関数のデフォルト挙動が変更されました。 「デフォルトではキャッシュされない(=毎回最新を取得するSSR的な挙動)」 になっています。

以前の仕様ではデフォルトがキャッシュ(SSG)でしたが、これが逆転しました。より直感的なWeb標準の挙動(GETリクエストは最新を取得する)に合わせた変更です。

実装パターンの例

データ取得のコード例を見てみましょう。

パターンA: 毎回最新を取得する (SSR)

デフォルトの挙動です。アクセスするたびにAPIを叩いて最新データを表示します。

// 特別なオプションは不要(最新仕様)
const res = await fetch("https://api.example.com/data");

パターンB: ビルド時に取得してキャッシュする (SSG)

ブログ記事のように、ビルド時に一度だけ取得すれば良い場合は force-cache を指定します。

// キャッシュを強制する(SSGとして動作)
const res = await fetch("https://api.example.com/posts", {
  cache: "force-cache",
});

パターンC: 一定時間ごとに更新する (ISR)

「基本はキャッシュしたいけど、1時間おきに更新したい」といった場合は revalidate オプションを使います。これを ISR (Incremental Static Regeneration) と呼びます。

// 3600秒(1時間)ごとにデータを更新
const res = await fetch("https://api.example.com/news", {
  next: { revalidate: 3600 },
});

サーバーコンポーネントとクライアントコンポーネント

Next.js App Router にはもう一つ重要な概念があります。

Server Components (デフォルト)

Next.js のコンポーネントは、デフォルトでは サーバーコンポーネント として扱われます。
これらはサーバー側でのみ実行され、結果のHTMLだけがブラウザに届きます。

  • ✅ データベースへの直接アクセスが可能
  • ✅ APIキーなどの秘密情報を隠せる
  • ✅ JavaScriptコードがブラウザに送られないので高速

Client Components ("use client")

ボタンのクリックイベント(onClick)や、フック(useState, useEffect)を使いたい場合は、ファイルの先頭に "use client" と宣言します。
これにより、そのコンポーネントはブラウザ側でJavaScriptとして動作するようになります。

sample.tsx
"use client"; // これを書くとクライアントコンポーネントになる

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0); // フックが使える
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

** 使い分けのコツ** :
基本はサーバーコンポーネントで作り、ユーザーが操作する部分(ボタン、フォームなど)だけを小さなクライアントコンポーネントとして切り出すのが「Next.js流」の設計です。

まとめ

  • SSG : ビルド時に作る(速い・キャッシュ) -> cache: 'force-cache'
  • SSR : アクセスのたびに作る(最新) -> fetch のデフォルト
  • ISR : 定期的に作り直す -> revalidate
  • Component : 基本はサーバー側。操作が必要なら "use client"

少し複雑に見えるかもしれませんが、コードを書きながら「ここはキャッシュしたいな」「ここは最新がいいな」と意識することで自然と身についていきます。
次章では、設定ファイルや環境変数について触れていきます。

更新履歴

  • 2025-01-04 : ページのレイアウト崩れ・誤字を修正しました。