はじめに
Next.js の SG + ISR (with Apollo) の仕組みを作りながら学んでみたシリーズ
このシリーズでは、Hasuraで用意した仮想のユーザーデータを外部APIとして取得しながら、
ユーザーの一覧ページと詳細ページを作りながら、SGと ISRを学ぶ記事です。
今回は、getStaticProps と getStaticPaths の理解と必要な実装について書きます。
目次
- 実装
- 検証
SGという用語に関して
SSGと言ったり、SGと言ったりするかもしれませんが、SSGはかつての呼び方なのでSG(Static Generate)に統一して書こうと思います。
仕組みは同じものだと思ってください。
最終的なゴール
以下のような構成のアプリを作ることです。
目的
- 仕事で使っている技術のキャッチアップと復習
- 使う可能性がある技術の理解度向上
pre-renderingについて
(意味を先に言うと、事前にHTMLを生成することです。)
Next.jsにおいて、重要な概念にpre-rendering
があります。
Next.jsは、デフォルトで全てのページでpre-rendering
しています。
ちなみに、React単体にはpre-rendering
の機能はありません。
なので、通常のReactで構築されたページよりもSEO的なメリットもあるかもです。
hydration
pre-rendering
されると、HTMLは必要最低限のJSコードとともに生成されます。
ブラウザによるロード時にこのJSが実行され、ページが完全にインタラクティブなものになります。
これをハイドレーション(hydration)と呼びます。
pre-renderingには二種類ある
pre-rendering
には二種類あります。
- 外部データを必要としないpre-rendering
- 外部データを必要とするpre-rendering
- 外部API(本記事ならHasuraなど)から取得してきたデータを一覧表示するページを作成したいとき
- そんなときに使用するのがgetStaticProps
- 外部API(本記事ならHasuraなど)から取得してきたデータを一覧表示するページを作成したいとき
getStaticPropsとgetStaticPathsの要点
- getStaticProps
- ビルド時に静的なファイルを生成し、ページコンポーネントで使用する値を用意する
- Next.jsで
pre-rendering
を行う際に、外部データが必要な時に使用する関数-
pre-rendering
: webページにアクセスする前にページを表示するのに必要なHTMLを構成しておく」という意味です
-
- getStaticPaths
- ビルド時にレンダリングする必要のあるパスのリストを生成する
これらの関数はクライアント側での実行でなく、必ずサーバーサイドで実行されます。
getStaticProps
getStaticProps
とgetStaticPaths
はSG用のAPIで、静的なデータを事前(ビルド時)に生成してくれます。
クライアント側で実行されず、サーバーサイドで実行されますが、アクセスの度にSSRはしません。
ビルド時にデータを取得し静的なファイルを事前に生成します。
なので、再ビルドしない限りいつアクセスしても同じ結果です。
getStaticPaths
のちのち説明するので、getStaticPathsの概要も把握しておきます。
getStaticPaths
はDynamic Routes
利用時にも静的なファイルを生成するためのAPIです。
こちらも、getStaticProps
と同様に、再ビルドしない限り、いつアクセスしても結果は同じです。
Dynamic Routesとは
Next.jsでは、pages/
配下でファイル名にブラケット([]
)を使用することで自動的にダイナミックルーティングされる仕組みのことです。
ダイナミックルート用のファイルでは、getStaticPaths
とgetStaticProps
の関数が必要です。
このシリーズ内の今後の記事で実装していきます。
実装
本記事で必要な部分だけ実装しました。
// GetStaticProps 用の型
import { GetStaticProps } from 'next'
import { initializeApollo } from '../lib/apolloClient'
// GetStaticProps で、ユーザーのリストを取得するのでqueriesからimport
import { GET_USERS } from '../queries/queries'
// GET_USERSの型
import { GetUsersQuery } from '../types/generated/graphql'
// ビルド時にサーバーサイドで実行される
export const getStaticProps: GetStaticProps = async () => {
// サーバーサイドでinitializeApolloを実行し、apolloClientを生成
const apolloClient = initializeApollo()
// 生成したapolloClientで、クエリ(GET_USERS)をHasuraに投げる
// await で同期化して、{ data } で受け取っている
const { data } = await apolloClient.query<GetUsersQuery>({
query: GET_USERS,
})
// usersという名前にして、user情報を返している
//
return {
props: { users: data.users },
revalidate: 1,
}
}
revalidate
関数getStaticProps
からreturn
するオブジェクトの中で、revalidate
というキー名に対して数値を指定します。
この単位は秒数です。なので、ここでは 1 ですから 1 秒という時間を指定しています。
revalidate
を指定すると、自動的にISRが有効化されます。
revalidate
をたとえば 1秒に指定すると、getStaticProps
を使ってSGが行われる各ページについて、1秒間はこれまでと同様に静的な HTML(のキャッシュ)をサーブします。
しかし、1秒経過した後に初めてユーザーからリクエストがあったタイミングで、そのリクエストに対してはすでに構築済みのHTML(のキャッシュ)を返しつつ、バックグラウンドでデータの再取得および再レンダリングを行いページを再生成し、次のリクエストに対しては再生成したページのキャッシュを返します。
これにより、時間の経過に応じて内容が変化する部分でも、アプリ全体を再ビルドすることなくその変化を反映させることができます。
今は秒数を 1秒として説明しましたが、データの性質に応じてこの秒数を調整できます。
また、revalidate
で指定した時間の経過後にリクエストが行われ、ページを再生成している間は、再生成する前の(つまり、生成済みの)HTML(のキャッシュ)を返すので、ページを再生成するタイミングで応答が遅くなるというようなことはありません。
またデータの再取得に失敗するなどしてページの再生成ができなかった場合は、過去にサーブしていたキャッシュがその後もサーブされます。
まとめ
今回は、getStaticProps と getStaticPaths の理解と必要な実装について書きました。
参考
次回
アウトプット100本ノック実施中