Pages

このドキュメント、はNext.jsバージョン9.3以上を対象としています。 古いバージョンのNext.jsを使用する場合は、過去のドキュメントを参照してください。

Next.js では、ページ(page)というのは pages ディレクトリ内の .js , jsx, .ts, .tsxファイルから export されたReact コンポーネント のことです。 それぞれのページのルーティングはファイル名によって決まります。

: 以下のような React コンポーネントを export する pages/about.js というファイルを作成すると、/aboutへとアクセスできるようになります。

function About() {
  return <div>About</div>;
}

export default About;

Pagesにおける動的なルーティング

Next.js の pages は動的なルーティングをサポートしています。 例えば、pages/posts/[id].jsというファイルを作成すると、posts/1, posts/2などにアクセスできます。

動的なルーティングについてさらに知るには、動的なルーティングのドキュメント をご覧ください。

プリレンダリング

通常、Next.js はそれぞれのページを事前にレンダリングします。 つまり、クライアント側の JavaScript でページ全体を生成する代わりに、それぞれのページの HTML をあらかじめ生成します。 プリレンダリングは優れたパフォーマンスと SEO をもたらします。

生成されたそれぞれの HTML には、そのページの生成に最低限必要な JavaScript コードが関連事項づけられています。 ページがブラウザから読み込まれると、JavaScript コードが走りページをインタラクティブなものにします。(この処理はハイドレーションと呼ばれています。)

プリレンダリングの2つの方式

Next.js ではプリレンダリングに関して静的生成(Static Generation)サーバーサイドレンダリング(Server-side Rendering)の 2 つの方式が利用可能です。 これらの違いは、HTML をいつ生成するかです。

重要なのは、Next.js ではどちらのプリレンダリング方法を用いるかを、それぞれのページに対して選ぶことができるということです。 つまり、ほとんどのページには静的生成を用い、残りのページにはサーバーサイドレンダリングを用いるといった、"ハイブリッド"な構成で Next.js アプリを作ることができます。

パフォーマンスの観点から、サーバーサイドレンダリングよりも静的生成を用いることを推奨しています。 静的に生成されたページは CDN によりキャッシュされ、パフォーマンスが高まります。ただし、サーバーサイドレンダリングを選択せざるを得ない場合もあります。

クライアントサイドレンダリングも静的生成やサーバーサイドレンダリングと同様にいつでも用いることができます。 つまり、ページの特定部分をクライアント側の JavaScript で丸ごとレンダーしても良いです。 これについてさらに知りたい場合には、データ取得のドキュメントをご覧ください。

静的生成(推奨)

サンプル

ページを静的生成するということは、そのページの HTML をビルド時に生成するということです。 本番用のアプリケーションでは、next buildを実行すると HTML が生成されます。 この HTML はリクエストの度に再利用され、CDN によりキャッシュが可能です。

Next.js では、外部データの取得の有無に関わらずページの静的生成が可能です。それぞれのケースについて見ていきましょう。

外部データの取得がない場合の静的生成

通常、Next.js はデータを取得せずに静的生成によってページをプリレンダリングします。以下がその例です。

function About() {
  return <div>About</div>;
}

export default About;

このページは外部からのデータ取得が必要ないことに留意してください。 このような場合、Next.js はビルド時に 1 ページ当たり 1 つの HTML ファイルを生成します。

外部データの取得がある場合の静的生成

ページによってはプリレンダリング時に外部のデータを取得しなければならない場合があります。 これには以下 2 つのシナリオのいずれかあるいは両方が考えられます。 それぞれのケースにおいて、Next.js の提供する以下の関数を用います。

  1. ページのコンテンツが外部データに依存する場合、getStaticPropsを用いてください。
  2. ページのパス(path)が外部データに依存する場合、getStaticPathsを用いてください(通常、getStaticPropsと合わせて用いられます)。

シナリオ 1: ページのコンテンツが外部データに依存する場合

: ブログのページが CMS (コンテンツ管理システム)から投稿した記事を取得する必要がある場合。

// TODO: ページをプリレンダリングする前に、
//       (APIのエンドポイントをコールして)`posts`を取得する必要あり
function Blog({ posts }) {
  return (
    <ul>
      {posts.map(post => (
        <li>{post.title}</li>
      ))}
    </ul>
  );
}

export default Blog;

プリレンダリング時にデータを取得するために、Next.js では getStaticProps と呼ばれる async 関数を同じファイルから export します。 この関数はビルド時に呼ばれ、取得されたデータをページのプリレンダリング時の props に渡します。

function Blog({ posts }) {
  // 記事のレンダー
}

// この関数はビルド時に呼ばれる
export async function getStaticProps() {
  // 投稿記事を取得する外部APIエンドポイントをコール
  const res = await fetch('https://.../posts');
  const posts = await res.json();

  // { props: posts }を返すことで、ビルド時にBlogコンポーネントが
  // `posts`をpropとして受け取れる
  return {
    props: {
      posts
    }
  };
}

export default Blog;

getStaticPropsの動作についてさらに知るためには、データ取得のドキュメントをご覧ください。

シナリオ 2: ページのパス(path)が外部データに依存する場合

Next.js では動的なルーティングによるページの生成が可能です。例えば、idに紐づくブログ投稿を表示するためには、pages/posts/[id].jsというファイルを作成します。 これにより、posts/1にアクセスすると id: 1 の投稿内容が表示されます。

動的ルーティングについてさらに知るためには、動的ルーティングのドキュメントをご覧ください。

しかしながら、どの id をビルド時にプリレンダリングするかが外部データに依存する可能性があります。

: データベースに id: 1 のブログ記事のみが追加された場合を考えてみましょう。この場合、ビルド時にプリレンダリングによってページを生成したいのは posts/1 のみです。

後になって id: 2 のブログ記事を追加するとしましょう。今度はビルド時に posts/2 もプリレンダリングする必要があります。

つまり、プリレンダリングするページのパスは外部のデータに依存します。外部データに依存するパスを扱うために、Next.js では getStaticPaths という async 関数を export します。(今回の場合、pages/posts/[id].jsに追加します。)

// この関数はビルド時に呼ばれる
export async function getStaticPaths() {
  // 記事を取得する外部APIのエンドポイントをコール
  const res = await fetch('https://.../posts');
  const posts = await res.json();

  // 記事にもとづいてプリレンダするパスを取得
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // 設定したパスのみ、ビルド時にプリレンダ
  // { fallback: false } は、他のルートが404になるという意味
  return { paths, fallback: false };
}

pages/posts/[id].jsは、idのブログ記事の内容を取得してページをプリレンダリングするために、getStaticPropsも合わせて export する必要があります。

function Post({ post }) {
  // 記事のレンダー
}

export async function getStaticPaths() {
  // ...
}

// この関数もビルド時に呼ばれる
export async function getStaticProps({ params }) {
  // `params`は`id`の記事内容を含む
  // ルートが/posts/1とすると、params.idは1となる
  const res = await fetch(`https://.../posts/${params.id}`);
  const post = await res.json();

  // propsを通じてpostをページに渡す
  return { props: { post } };
}

export default Post;

getStaticPathsの動作についてさらに知りたい場合には、データ取得のドキュメントをご覧ください。

どのような場合に静的生成を行うべきか?

ページは一度だけビルドしてしまえば CDN によって配信できるので、(データ取得の有無に関わらず)可能な限り静的生成を推奨しています。 これにより、それぞれのリクエストに対してサーバー側で HTML を生成するよりもずっと高速になります。

静的生成は以下のような様々なページに対して行うことができます。

  • マーケティングのページ
  • ブログ記事やポートフォリオ
  • e コマースの製品リスト
  • ヘルプやドキュメント

「このページはユーザのリクエストより前にコンテンツを準備しておくことが可能か?」と自分自身に問いかけてみてください。 もし答えが YES なら、静的生成を選択すべきでしょう。

一方、ユーザーのリクエストよりも前にページの内容を準備できない場合、静的生成は推奨されません。 ページに含まれる情報が頻繁に更新され、リクエストの度に内容が変わることもあり得るでしょう。

このような場合には、以下の方法をとることができます。

  • クライアントサイドレンダリングと静的生成を併用する: ページの一部のプリレンダリングを一旦飛ばし、クライアント側の JavaScript を使って残りを表示させます。 このアプローチについてさらに知るためには、データ取得のドキュメントをご覧ください。
  • サーバーサイドレンダリングを用いる: Next.js がそれぞれのリクエストに対してプリレンダリングします。 CDN によるキャッシュができないので表示が遅くなりますが、常に最新の情報が表示されます。このアプローチについてこれから説明します。

サーバーサイドレンダリング

"SSR"や"ダイナミックレンダリング"とも呼ばれます。

サーバーサイドレンダリングを用いると、ページの HTML がリクエストの度に生成されます。

サーバーサイドレンダリングを使うためには、getServerSidePropsと呼ばれる async 関数を export する必要があります。この関数はリクエストごとにサーバー側で呼ばれます。

例えば、ページの表示に用いるデータ(外部の API から取得する)が頻繁に更新される場合を考えましょう。この場合、以下のように getServerSideProps を追加することで、データを取得して Page に渡す処理を行うことができます。

function Page({ data }) {
  // 記事のレンダー
}

// この関数はリクエストのたびに呼ばれる
export async function getServerSideProps() {
  // 外部のAPIからデータを取得
  const res = await fetch(`https://.../data`);
  const data = await res.json();

  // propsを通してdataを渡す
  return { props: { data } };
}

export default Page;

見ての通り、getServerSidePropsgetStaticProps とよく似ています。両者の違いは、getServerSidePropsがビルド時ではなくリクエストの度に呼ばれることです。

getServerSidePropsの動作についてさらに知りたい場合には、データ取得のドキュメントをご覧ください。

まとめ

Next.js のプリレンダリングの方法として、以下の 2 つについて説明しました。

  • 静的生成(推奨): HTML はビルド時に生成され、それぞれのリクエストに対して再利用されます。 静的生成では、ページの内容を export するか、getStaticProps(必要であれば getStaticPaths も)を export してください。 ユーザーからのリクエストの前に, ページをプリレンダリングできるということは素晴らしいことです。クライアントサイドレンダリングと併用することで、追加のデータもレンダリングできます。
  • サーバーサイドレンダリング: HTML はリクエストの度に生成されます。サーバーサイドレンダリングを行うためには、getServerSidePropsexport してください。 サーバーサイドレンダリングは静的生成に比べて動作が遅くなるため、どうしても必要な場合にのみ使用してください。

関連事項

以下のセクションを次に読むことをお勧めします。