​【Next.jsチュートリアル解説】第8章:静的レンダリングと動的レンダリング

Next.jsの静的レンダリング(SSG)と動的レンダリング(SSR)の違いを比較した図。SSGはCDNのキャッシュから高速配信し、SSRはリクエストごとにサーバーで最新データを取得してページを生成する。 プログラミング

前回の第7章では、ダッシュボードにデータベースからの実際のデータを組み込み、並列データ取得(Promise.all)による最適化を行いました。

しかし、前章の最後で触れた通り、現在のアプリケーションにはまだ「データが更新されても画面に反映されない(静的レンダリングのままになっている)」という課題や、「最も遅いデータ取得に全体が引きずられる」という問題が残っています。

今回は、Next.jsにおける「静的レンダリング」と「動的レンダリング」の仕組みの違い、そしてそれがパフォーマンスにどう影響するのかを詳しく解説します。

1. 静的レンダリング(Static Rendering)とは?

静的レンダリングでは、データの取得とページのレンダリングがビルド時(アプリケーションをデプロイする時)またはデータの再検証時にサーバー上で行われます。

一度生成されたHTMLやアセットはキャッシュされ、ユーザーがアクセスするたびにそのキャッシュされた結果がそのまま返されます。

Next.jsの静的レンダリング(SSG)の仕組みを解説する図。ビルド時に生成したHTMLをCDNにキャッシュして高速配信する流れと、ブログや製品紹介ページに適した用途、サーバー負荷の軽減やSEOのメリットを示している。

静的レンダリングのメリット

  • ウェブサイトの高速化: VercelなどのCDN(エッジネットワーク)にキャッシュされるため、世界中のユーザーへミリ秒単位で超高速にコンテンツを配信できます。
  • サーバー負荷の軽減: リクエストごとにサーバーが動的にHTMLを再生成する必要がないため、コンピューティングコストを大幅に削減できます。
  • 高いSEO効果: ページ読み込み時に既に完全なコンテンツが存在するため、検索エンジンのクローラーがインデックスを作成しやすくなります。

適しているケース

  • ブログ記事、製品の紹介ページ、ドキュメントなど、ユーザー間で共通の静的なデータ。

逆に、ユーザーごとに内容が変わり、頻繁にデータが書き換わるダッシュボードアプリには、デフォルトの静的レンダリングは適していません。

2. 動的レンダリング(Dynamic Rendering)とは?

動的レンダリングでは、コンテンツはビルド時ではなく、ユーザーがページにアクセスしたその瞬間(リクエスト時)にサーバー上でレンダリングされます。

Next.jsの動的レンダリング(SSR)の仕組みを解説する図。ユーザーのアクセス時にサーバーがCookieやURL検索パラメータ、データベースの情報を取得してHTMLを生成し、最新かつユーザー固有のコンテンツを表示する流れを示している。

動的レンダリングのメリット

  • リアルタイムデータ: データベースの最新変更や頻繁に更新されるデータを常に正確に表示できます。
  • ユーザー固有のコンテンツ: ダッシュボードやユーザープロファイルなど、パーソナライズされた情報を安全に提供できます。
  • リクエスト時の情報へのアクセス: CookieやURLの検索パラメータ(Query Parameters)など、ユーザーがアクセスした瞬間にしか分からない情報を使って処理を行えます。

3. 低速なデータ取得をシミュレートしてみる(ボトルネックの体感)

ダッシュボードのような動的アプリケーションにおいて、パフォーマンスを考える上で非常に重要な教訓があります。それは、「動的レンダリングでは、アプリケーションの速度は最も遅いデータ取得速度に依存する」ということです。

これを実際に体験するため、チュートリアルではあえて遅延を発生させるシミュレーションを行います。

実験方法

/app/lib/data.ts 内にある fetchRevenue() 関数の中の console.log と setTimeout のコメントアウトを解除します。

export async function fetchRevenue() {
  try {
    console.log('Fetching revenue data...');
    // デモ目的で意図的に3秒の遅延を発生させる(※本番環境では絶対にやらないこと!)
    await new Promise((resolve) => setTimeout(resolve, 3000));
 
    const data = await sql<Revenue[]>`SELECT * FROM revenue`;
 
    console.log('Data fetch completed after 3 seconds.');
    return data;
  } catch (error) {
    console.error('Database Error:', error);
    throw new Error('Failed to fetch revenue data.');
  }
}

この状態で新しいタブを開き、http://localhost:3000/dashboard/ にアクセスしてみてください。

何が起きるか?

  • ページの読み込みが明らかに 3秒間ブロック されます。
  • ターミナルには、通信の開始と完了のログが時間差で表示されます。
ページ読み込みのブロックしている時間が表示されるターミナル画面のスクリーンショット

たった一つのデータ取得(この場合は売上データ)が遅いだけで、ページ全体全体の表示が丸ごと待たされてしまう——これが、実務のWeb開発で私たちが直面する大きなボトルネックです。

「すべてを事前に準備するか、その場で組み立てるか」

Next.jsのチュートリアルを進めていて、第8章の「静的レンダリングと動的レンダリング」に差し掛かったとき、生産工場管理の現場と重なる部分あると感じましたが。

プログラムの世界では、ページをあらかじめビルド時に全部作り上げておく「静的(Static)」と、ユーザーがアクセスした瞬間にサーバーが組み立てる「動的(Dynamic)」という2つのアプローチがあります。

1. 「静的レンダリング」は、工場あらかじめ作る「完成品パーツ」

静的レンダリングは、いわば「あらかじめ工場で完璧に組み立てて倉庫に保管しておく既製品」のようなものです。

  • メリット: 注文が入ったら(ユーザーがアクセスしたら)倉庫から一瞬で取り出して出荷するだけなので、スピードが爆発的に速い。サーバーの労力もほとんどかかりません。
  • 向いているもの: ブログの記事や会社のホームページなど、「誰が見ても同じ情報」で、頻繁に内容が変わらないもの。

しかし、これを「常に刻一刻と状態が変わる現場の稼働状況ボード(ダッシュボード)」に使おうとすると問題が起きます。倉庫から持ってくる既製品のデータが古いため、現場で機械が動いてステータスが変わっていても、画面には「昨日時点の情報」がそのまま表示されてしまうのです。

2. 「動的レンダリング」は、その場で図面を見て組み立てる「特注品」

一方の動的レンダリングは、「ユーザーから注文書を受け取ったその瞬間に、最新の部品と図面を取り出して、工場で一から組み立てて納品する特注品」です。

  • メリット: データベースの最新情報を反映できるため、常にリアルタイムで正確なデータ(売上や未払い請求書の数など)を表示できる。ユーザー固有の認証情報やCookieにも対応できる。
  • 向いているもの: 今回作っているダッシュボードや、ユーザーのマイページなど。

3. 動的レンダリングの落とし穴:「一番遅い工程」に全体が引きずられる

「その場で組み立てる(動的)」ということは、もし組み立ての工程の中に一つでも「時間がかかる作業」が混ざっていると、それが完了するまで次の作業が一切進まないということです。

工場でいえば、4つの組み立てラインのうち、1つだけ「海外から取り寄せる特殊パーツの到着を待つライン」があったとしたらどうでしょう? 他の3つのパーツが秒速で組み上がっていても、その1つのせいで出荷全体のトラックが3秒間足止めを食らうことになります。

Webアプリケーションの世界でも同じで、動的レンダリングにおいては「アプリ全体の速度は、最も遅いデータ取得のスピードに引きずられる」というボトルネックが生まれます。

まとめ:適材適所のバランスが肝心

  • スピードと効率を取るなら静的(Static)
  • リアルタイム性と正確さを取るなら動的(Dynamic)

「じゃあ、遅いデータがあるときはどうすれば?」という自然な疑問に対する答えが、まさに次の章で学ぶ「ストリーミング(Streaming)」に繋がっていきます。

Webのフロントエンドでは「届いたパーツから順次画面に流し込んでいく」という発想が非常に重要だと実感させられました。

まとめ・次のステップ

第8章では、以下のポイントについて学びました。

  1. 静的レンダリングは高速でサーバー負荷が低い反面、常に最新データが変わるダッシュボードには不向きであること。
  2. 動的レンダリングはリアルタイムな最新データを扱えるが、「最も遅いデータ取得が完了するまでページ全体がブロックされる」という弱点があること。

「もしデータベースや外部APIの応答が遅かったら、ユーザーはずっと白い画面(またはローディング)を見せられ続けるのか……?」という疑問が湧いてきますよね。

次回の 第9章「ストリーミング(Streaming)」 では、この「遅いデータ取得にページ全体が引きずられる問題」を華麗に解決する、Next.jsの強力な機能について解説していきます!

コメント