【Next.js和訳】Basic Features/Pages
この記事について
この記事は、Basic Features/Pagesの記事を和訳したものです。
記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。
Pages
Next.jsにおいて、pageは、pages
ディレクトリ内の.js
、.jsx
、.ts
、.tsx
ファイルからエクスポートされたReact Componentです。各ページは、そのファイル名に基づいてルートに関連付けられます。
例:以下のようなReactコンポーネントをエクスポートするpages/about.js
を作成すると、/about
からアクセスできるようになります。
function About() {
return <div>About</div>
}
export default About
動的ルートを持つページ
Next.jsは動的なルートを持つページをサポートしています。例えば、pages/posts/[id].js
というファイルを作成すると、posts/1
、posts/2
などでアクセスできるようになるということです。
ダイナミックルーティングについて詳しく知りたい方は、Dynamic Routing documentationをご覧ください。
プリレンダリング
デフォルトでは、Next.jsはすべてのページを プリレンダリング します。これは、Next.jsが各ページのHTMLを、クライアントサイドのJavaScriptですべて処理するのではなく、事前に生成することを意味します。プリレンダリングを行うことで、パフォーマンスやSEOの向上につながります。
生成された各HTMLには、そのページに必要な最小限のJavaScriptコードが関連付けられています。ページがブラウザに読み込まれると、そのJavaScriptコードが実行され、ページが完全にインタラクティブになります。(このプロセスを hydration と呼びます)。
プリレンダリングの2つの形態
Next.jsには2つのプリレンダリングの形式があります。静的生成とサーバーサイドレンダリングです。その違いは、ページのHTMLを生成するタイミングにあります。
- 静的生成(推奨):HTMLは構築時に生成され、各リクエストで再利用されます。
- サーバーサイドレンダリング:HTMLは各リクエストで生成されます。
重要なのは、Next.jsでは、各ページで使用するプリレンダリングのフォームを選択できることです。ほとんどのページでは静的生成を使用し、その他のページではサーバーサイドレンダリングを使用することで、「ハイブリッド」なNext.jsアプリを作成することができます。
パフォーマンス上の理由から、サーバーサイドレンダリングよりも静的生成を使用することをお勧めします。静的生成されたページは、追加設定なしでCDNにキャッシュされ、パフォーマンスが向上します。ただし、場合によっては、サーバーサイドレンダリングが唯一の選択肢となることもあります。
静的生成やサーバーサイドレンダリングとともに、クライアントサイドレンダリングを使用することもできます。これは、ページの一部をクライアントサイドJavaScriptで完全にレンダリングできることを意味します。詳細については、Data Fetchingのドキュメントをご覧ください。
静的生成(推奨)
例
- WordPressの例 (Demo)
- マークダウンファイルを使ったブログスターター (Demo)
- DatoCMSの例 (Demo)
- TakeShapeの例 (Demo)
- SANITYの例 (Demo)
- Prismic CMSの例 (Demo)
- contentfulの例 (デモ)
- strapiの例 (デモ)
- Preprの例 (Demo)
- Agility CMSの例 (デモ)
- Cosmicの例 (Demo)
- ButterCMSの例 (Demo)
- Storyblokの例 (Demo)
- GraphCMSの例 (Demo)
- Kontentの例 (Demo)
- 静的ツイートのデモ
ページが静的生成を使用する場合、ページの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が提供する以下の機能を利用することができます。
- ページの コンテンツ が外部データに依存している:
getStaticProps
を使用します。 - ページの パス が外部データに依存している場合:通常は
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
のブログ記事を表示することができます。
しかし、ビルド時にどの 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でページをキャッシュできないため速度は遅くなりますが、プリレンダリングされたページは常に最新の状態に保たれます。この方法については後述します。
サーバーサイド・レンダリング
ページがサーバーサイドレンダリングを使用する場合、ページの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
ご覧の通り、getServerSideProps
は getStaticProps
と似ていますが、違いは getServerSideProps
がビルド時ではなく、全てのリクエスト時に実行されることです。
getServerSideProps
の動作について詳しく知りたい方は、Data Fetching documentationをご覧ください。
Summary
Next.jsのプリレンダリングについて、2つの形式を取り上げました。
-
Static Generation (Recommended):HTMLはbuild timeに生成され、各リクエストで再利用されます。ページに静的生成を使用するには、ページコンポーネントをエクスポートするか、
getStaticProps
(必要に応じてgetStaticPaths
も)をエクスポートします。ユーザーのリクエストに先立ってプリレンダリングを行うことができるページには最適です。また、追加データを取り込むために、クライアントサイドレンダリングと一緒に使用することもできます。 -
サーバーサイドレンダリング:HTMLはリクエストごとに生成されます。ページでサーバサイドレンダリングを使用するには、
getServerSideProps
をエクスポートします。サーバーサイドレンダリングは静的生成よりもパフォーマンスが低下するため、絶対に必要な場合にのみ使用してください。
もっと詳しく
次のセクションをお読みになることをお勧めします。
Discussion