【Next.js】【入門/チュートリアル】fallbackとIncremental Static Regeneration(ISR)
記事を書く動機
下記で、Next.jsの公式サイトのチュートリアルを行ったのですが、チュートリアルだけでは少しわかりづらかったfallback
とIncremental Static Regeneration(ISR)
について備忘も兼ねてスクラップから切り出して記事にしようと思いました。
【チュートリアルのスクラップ】
注意事項
Next.jsを始めたばかりなので、認識が間違っている部分、わかりずらい部分があるかもしれないです。
その場合は、コメントいただけますと幸いです。
Dynamic Routes
Dynamic Routesの概要
fallback
とIncremental Static Regeneration(ISR)
を理解するためには、まずDynamic Routes
について理解できていないといけない気がします。
Dynamic Routes
はパスパラーメータによって動的にルーティングを変えたい時に使います。
例えば、下記のような2つのURLがあったとして、ルーティングをパスパラーメータによって動的に変えたい場合に使用します。
- /posts/1
- /posts/2
Dynamic Routesの実装方法
[]
を使う
ファイル名にDynamic Routes
はファイル名に[]
を使うことで実現できます。
例えば、下記のように[id].js
とすることで、id
部分を動的にルーティングすること(/posts/1
や/posts/2
など)が可能になります。
--project
--pages
-- posts
-- [id].js
[].js
ファイルの実装
また、Dynamic Routes
はgetStaticPaths
メソッドで予めパスパラーメータとして取りうる値を指定することでルーティングが可能となります。
もう少し詳しく説明すると、getStaticPaths
メソッドでpaths
とfallback
を返しており、
-
paths
はパスパラーメータとして取りうる値を定義し、 -
fallback
は定義したpaths
以外のアクセスがあった場合どのような処理を行うかを決めます。(詳しくは後述)
import Layout from '../../components/layout'
export default function Post() {
return <Layout>...</Layout>
}
export async function getStaticPaths() {
return {
// pathsが必須。
paths: [
{
// パスパラーメータとして取りうる値をidをKeyにしたparamsObjectで定義する。
params: {
// `/posts/1`へのルーティングが可能。
// idはファイル名に合わせる。今回は[id].jsなのでKeyが`id`となる
id: '1',
},
},
{
params: {
// `/posts/2`へのルーティングが可能。
id: '2',
},
},
],
// fallbackが必須。詳しくは後述。
fallback: false,
};
}
// 上記で定義したをparamsObjectをgetStaticPropsの引数で受け取る。
// `/posts/1`へのルーティングの場合、params = {id: '1'}
export async function getStaticProps({ params }) {
// 受け取ったパスパラーメータをもとに処理を行う
}
export default Post
fallback
上記で説明したようにfallback
は定義したpaths
以外のアクセスがあった場合どのような処理を行うかを決めます。
上記の例で言うと、paths
に定義されていない/posts/3
などからアクセスがあった場合にどのような処理を行うかを決めるということです。
fallback: false
の場合
paths
に定義されていないパスからのアクセスがあった場合、404ページを返却します。
上記の例で言うと、paths
に定義されていない/posts/3
からのアクセスがあった場合に404ページを返却します。
fallback:true
の場合
paths
に定義されていないパスからのアクセスがあったとしても、404ページが返却されません。
代わりに以下のようなフローで、新たに静的ファイルを作成し、クライアント側に返却します。
上記の例で言うと、
-
/posts/3
のパスがRequestとして来ます。
※paths
に定義されていないidであるが、fallback:true
なので、404ページを返却しません。 - 裏側でサーバー側が
getStaticProps
を実行し、id=3に紐づく静的なファイルを生成します。 - 生成が完了したら作成した静的ファイルを返します。
- これ以降の
/posts/3
は②で作成した静的ファイルを返します。
以下、サンプルコードです。
import { useRouter } from 'next/router'
function Post({ post }) {
// fallbackの状態を監視できるuseRouter()を使用
const router = useRouter()
// 上記でいう②が完了するまで、router.isFallback = trueとなり、ローディング画面をを表示
if (router.isFallback) {
return <div>Loading...</div>
}
// Render post...
}
// Build時のみに実行する
export async function getStaticPaths() {
return {
// `paths`にid=1,2のみを定義。これらのパスはBuild時に生成される
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
// id=3を許容できるようにfallback: trueを設定する
fallback: true,
}
}
// Build時にはparams.id=1,2で実行
// もし、`/posts/3`が来た場合、裏側で非同期的にサーバー側が`getStaticProps`を実行
export async function getStaticProps({ params }) {
// 受け取ったパスパラーメータをもとに処理を行う
}
export default Post
fallback:true
の注意点
②で生成された静的ファイルは、一度生成されてしまうと、内容の更新があったとしても静的ファイル自体の更新はされません。
(SSGの性質上当たり前なことだと思いますが...)
つまり、②で一度静的ファイルが作成されたら④以降ではその静的ファイルをずっと参照することになります。
更新後、更新した静的ファイルを参照するためにはIncremental Static Regeneration(ISR)(後述)を使用します。
Incremental Static Regeneration(ISR)
ISRは動的コンテンツを事前Buildせずに(全てのページを生成するのではなく)、ページにアクセスしたときに初めてBuildします。
ISRでBuildした内容には有効期限(revalidate
)を設けることができ、有効期限を過ぎたページにアクセスされた場合は、前回ビルドされたコンテンツを返しつつも、裏側で再Buildをサーバー側にかけにいきます。
この機能が生まれた背景
ISRはNext.js 9.4から実装されたものです。
これ以前のSSGでのBuild方法は下記のようなデメリットがあり、それを解消するために生まれたようです。
- 膨大な数(数億、数兆規模)の静的ページをSSGで一度にBuildする場合、データの取得やHTMLの作成が膨大になり、Buildに時間がかかる
- ページが更新された際は再度全てのページをビルドしなおさないといけない
ISRは上記で説明したように、ページにアクセスしたときに初めてBuildするため、事前Buildでのページ数を減らすことができ、また、有効期限を過ぎたものは裏側で再Buildされるため、ページの更新を随時行うことができます。
ISRの実装方法
getStaticProps
の返り値にrevalidate
を設定すればISRが使えるようになります。
function Post({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
// 初回Build時にサーバー側で実行
// revalidateで設定した時間を過ぎ、かつRequestが来た時にサーバー側で再実行される
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
// revalidateを設定すればISRが使えるようになる。(単位は秒)
revalidate: 1,
}
}
export default Post
最後に
チュートリアルの際に少しわかりづらかったfallback
とIncremental Static Regeneration(ISR)
についてまとめてみました。
冒頭でも述べたように、Next.jsを始めたばかりなので、認識が間違っている部分、わかりずらい部分があるかもしれないです。
その場合は、コメントいただけますと幸いです。
Discussion