🚀

【Next.js和訳】Basic Features/Pages

11 min read

この記事について

株式会社 UnReact はプロジェクトの一環としてNext.js ドキュメントの和訳を行っています。

この記事は、Basic Features/Pagesの記事を和訳したものです。

記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。

Pages

このドキュメントは、Next.jsのバージョン9.3以降を対象としています。古いバージョンのNext.jsをお使いの方は、以前のドキュメントをご参照ください。

Next.jsにおいて、pageは、pagesディレクトリ内の.js.jsx.ts.tsxファイルからエクスポートされたReact Componentです。各ページは、そのファイル名に基づいてルートに関連付けられます。

:以下のようなReactコンポーネントをエクスポートするpages/about.jsを作成すると、/aboutからアクセスできるようになります。

pages/about,js
function About() {
  return <div>About</div>
}
export default About

動的ルートを持つページ

Next.jsは動的なルートを持つページをサポートしています。例えば、pages/posts/[id].jsというファイルを作成すると、posts/1posts/2などでアクセスできるようになるということです。

ダイナミックルーティングについて詳しく知りたい方は、Dynamic Routing documentationをご覧ください。

プリレンダリング

デフォルトでは、Next.jsはすべてのページを プリレンダリング します。これは、Next.jsが各ページのHTMLを、クライアントサイドのJavaScriptですべて処理するのではなく、事前に生成することを意味します。プリレンダリングを行うことで、パフォーマンスやSEOの向上につながります。

生成された各HTMLには、そのページに必要な最小限のJavaScriptコードが関連付けられています。ページがブラウザに読み込まれると、そのJavaScriptコードが実行され、ページが完全にインタラクティブになります。(このプロセスを hydration と呼びます)。

プリレンダリングの2つの形態

Next.jsには2つのプリレンダリングの形式があります。静的生成サーバーサイドレンダリングです。その違いは、ページのHTMLを生成するタイミングにあります。

重要なのは、Next.jsでは、各ページで使用するプリレンダリングのフォームを選択できることです。ほとんどのページでは静的生成を使用し、その他のページではサーバーサイドレンダリングを使用することで、「ハイブリッド」なNext.jsアプリを作成することができます。

パフォーマンス上の理由から、サーバーサイドレンダリングよりも静的生成を使用することをお勧めします。静的生成されたページは、追加設定なしでCDNにキャッシュされ、パフォーマンスが向上します。ただし、場合によっては、サーバーサイドレンダリングが唯一の選択肢となることもあります。

静的生成やサーバーサイドレンダリングとともに、クライアントサイドレンダリングを使用することもできます。これは、ページの一部をクライアントサイドJavaScriptで完全にレンダリングできることを意味します。詳細については、Data Fetchingのドキュメントをご覧ください。

静的生成(推奨)

ページが静的生成を使用する場合、ページの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. ページの パス が外部データに依存している場合:通常は getStaticProps に加えて getStaticPaths を使用します。

シナリオ1:ページの内容が外部データに依存している

を挙げます。あなたのブログページは、CMS(コンテンツマネジメントシステム)からブログ記事のリストを取得する必要があるかもしれません。

// TODO: `posts` を(何らかの 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 }) {
    // postsをレンダリング..
}
// この関数はビルド時に呼び出される
export async function getStaticProps() {
  // 外部のAPIエンドポイントを呼び出して投稿を取得する
  const res = await fetch('https://.../posts')
  const posts = await res.json()
  // { props: { posts } } を返すことでブログコンポーネントは
  // ビルド時に `posts` をプロップとして受け取ります。  
    return {
    props: {
      posts,
    },
  }
}
export default Blog

getStaticPropsの仕組みについては、Data Fetching documentationをご覧ください。

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

Next.jsでは、動的なルートを持つページを作成することができます。例えば、pages/posts/[id].jsというファイルを作成して、idに基づいて1つのブログ記事を表示することができます。これにより、posts/1にアクセスしたときに、id.1のブログ記事を表示することができます。

ダイナミックルーティングについて詳しく知りたい方は、Dynamic Routing documentationをご覧ください。

しかし、ビルド時にどの id を事前にレンダリングするかは、外部データに依存するかもしれません。

: データベースに1つのブログ記事(id: 1)しか追加していないとします。この場合、ビルド時には posts/1 だけをプリレンダリングしたいと思います。

その後、2つ目の記事を id: 2 で追加するかもしれません。そうすると、posts/2もプリレンダリングしたくなります。

これを処理するために、Next.jsでは、動的なページ(この例では、pages/posts/[id].js)から、getStaticPathsというasync関数をexportすることができます。この関数はビルド時に呼び出され、事前にレンダリングしたいパスを指定することができます。

// この関数はビルド時に呼び出される
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では、getStaticPropsをエクスポートする必要があります。これにより、このidを持つ投稿に関するデータを取得して、ページのプリレンダリングに使用することができます。

function Post({ 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()
  // postデータをprops経由でページに渡す
  return { props: { post } }
}
export default Post

getStaticPathsの仕組みについては、Data Fetching documentationを参照してください。

静的生成はいつ使うべきか

これは、ページを一度構築して CDN で配信することで、リクエストごとにサーバーがページをレンダリングするよりもはるかに高速になるからです。

Static Generationは、以下のような様々なタイプのページに使用できます。

  • マーケティングページ
  • ブログ記事
  • Eコマースの製品リスト
  • ヘルプとドキュメント

自分自身に問いかけてみてください。「ユーザーがリクエストする前に、このページを事前にレンダリングすることはできますか?答えがイエスであれば、Static Generationを選択すべきです。

逆に、ユーザーのリクエストに先んじてページをプリレンダリングできない場合は、Static Generationは良いアイデアではありません。例えば、頻繁に更新されるデータを表示するページで、リクエストのたびにページの内容が変わるような場合です。

このような場合には、以下のいずれかの方法があります。

  • クライアントサイドレンダリング で静的生成を行う:ページの一部を事前にレンダリングせずに、クライアントサイドJavaScriptを使用して入力することができます。この方法の詳細については、Data Fetching documentationを参照してください。
  • サーバーサイドレンダリング の使用:Next.jsは、リクエストごとにページをプリレンダリングします。CDNでページをキャッシュできないため速度は遅くなりますが、プリレンダリングされたページは常に最新の状態に保たれます。この方法については後述します。

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

SSR」や「Dynamic Rendering」とも呼ばれています。

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

ページでサーバーサイドレンダリングを使用するには、getServerSideProps という async 関数を export する必要があります。この関数は、リクエストごとにサーバから呼び出されます。

例えば、頻繁に更新されるデータ(外部のAPIから取得したもの)をページでプリレンダリングする必要があるとします。以下のように、このデータを取得して Page に渡す getServerSideProps を書くことができます。

function Page({ data }) {
  // dataをレンダリング
}
// これはすべてのリクエストで呼び出されます
export async function getServerSideProps() {
  // 外部APIからデータを取得する
  const res = await fetch(`https://.../data`)
  const data = await res.json()
  // プロップスを介してページにデータを渡す
  return { props: { data } }
}
export default Page

ご覧の通り、getServerSidePropsgetStaticProps と似ていますが、違いは getServerSideProps がビルド時ではなく、全てのリクエスト時に実行されることです。

getServerSidePropsの動作について詳しく知りたい方は、Data Fetching documentationをご覧ください。

Summary

Next.jsのプリレンダリングについて、2つの形式を取り上げました。

  • Static Generation (Recommended):HTMLはbuild timeに生成され、各リクエストで再利用されます。ページに静的生成を使用するには、ページコンポーネントをエクスポートするか、getStaticProps(必要に応じてgetStaticPathsも)をエクスポートします。ユーザーのリクエストに先立ってプリレンダリングを行うことができるページには最適です。また、追加データを取り込むために、クライアントサイドレンダリングと一緒に使用することもできます。
  • サーバーサイドレンダリング:HTMLはリクエストごとに生成されます。ページでサーバサイドレンダリングを使用するには、getServerSidePropsをエクスポートします。サーバーサイドレンダリングは静的生成よりもパフォーマンスが低下するため、絶対に必要な場合にのみ使用してください。

もっと詳しく

次のセクションをお読みになることをお勧めします。

https://nextjs.org/docs/basic-features/data-fetching

https://nextjs.org/docs/advanced-features/preview-mode

https://nextjs.org/docs/routing/introduction

https://nextjs.org/docs/basic-features/typescript#pages

Discussion

ログインするとコメントできます