【Next.js】特徴とIncremental Static Regenerationについて

エンジニア転職して、早いもので半年が経過しようとしています。
最近業務ではNext.jsで実装をしていますが、アウトプットも兼ねて学んだことを簡単にまとめていこうと思います。

# Next.jsとは
**Next.jsとは、Reactの機能を拡張するためのJavaScriptフレームワークです。**
2016年にVercel社によりバージョン1.0がリリースされ、現在も開発が継続されています。

https://nextjs.org/


# Next.jsの特徴
## SSR（Server Side Rendering）とSSG（Static Site Generator）

Reactは**SPA(Single Page Application)**として単一の巨大なJavaScriptを生成します。

SPAはブラウザによるページ遷移を行わずにコンテンツの切り替えなどを行うことで、ユーザー体験（UX）を大きく向上させることができますが、今までサーバー側で行っていたHTML生成をブラウザ側で行うことになるため、

- 初期ローディングの時間がかかったり、
- 通常のWebページと比べSEOの面で不利になる

というデメリットがあります。

それに対して、Next.jsはアプリケーションを**事前にページ単位で**レンダリングします。

クライアント側からのリクエスト時にレンダリングするのが**SSR(Server Side Rendering)**と呼ばれる機能です。
また2020年3月リリースのv9.3より、ビルド時にレンダリングする**SSG(Static Site Generation)**と呼ばれる機能も追加されました。

これらの機能により、各ページ読み込み時のダウンロードファイルサイズを削減できます。
またURLごとに個別のHTMLが生成されるので、SEOに有利です。

ちなみに、**SSRとSSGの切り替えはビルド時にNext.jsが自動的に判断**します。
getServerSidePropsなどSSR用のメソッドが使われていればビルド時には静的ファイルを作成しません。
反対に、それらが使われていなければビルド時に自動で静的ファイルの生成までやってくれます。（素晴らしい・・・）

## Next.jsはSSRのためのフレームワークではない
Next.jsはSSRのためのフレームワークという印象がありましたが、現在（v11.0）、下記のとおり**Static Site Generation(SSG)が推奨**されています。

>We recommend using Static Generation over Server-side Rendering for performance reasons. Statically generated pages can be cached by CDN with no extra configuration to boost performance.
[Basic Features: Pages | Next.js](https://nextjs.org/docs/basic-features/pages)

SSGは、**ビルド時にすべてのページを生成するため、リクエストごとにページ生成するSSRよりも高速**です。

Next.jsはこのパフォーマンスをウリにしていて、**「どや、ウチの速いやろ・・・ええからSSG使ってみ」**と言ってるわけなんですね。


# ISG（Incremental Static Generation）
SSGでは、**getStaticProps関数**により、ビルド時にデータを取得してページにデータを渡すことができます。

```javascript:index.jsx
export async function getStaticProps(context) {
 return {
   props: { 渡したいデータ }, 
 }
}
```

また、**getStaticPaths関数**により、一覧ページ→詳細ページのような動的な（臨機応変な、柔軟な）ページ遷移にも対応しています。

```javascript:index.jsx
export async function getStaticProps(context) {
 const postId = context.params.id // context.paramsによりpathsで指定したparamsを参照
 const post = postIDによるpostデータ取得処理

 return {
   props: { postId, post },
 }
}

export async function getStaticPaths() {
 return {
   paths: [ // 生成されるページのURLのパス一覧
       { params: { id: 'my-first-post' } },
       { params: { id: 'my-second-post' } },
       { params: { id: 'my-third-post' } }, 
   ],
   fallback: false
 }
}
```

上記コードでは、```https://example.com/posts/選んだid```にアクセスすると、idに対応したデータ内容が表示されたページを取得することができます。

getStaticPaths関数には必ずfallbackキーを記述します。

pathsにないパスに対してリクエストがあったときに、fallbackキーの値によって挙動の違いがあります。

```false``` ：404ページを返す
```true``` ：まずはデータ取得が必要な部分以外を返してからデータ取得が行われる
```blocking``` ：”データ取得が必要な部分以外を返す”という動作をブロックして（＝行わず）、データ取得が終わってからページ全体を返す（v10より追加）

getStaticPaths関数の例のように、段階的に（クライアント側からのリクエストにより）ページが静的に生成される機能の総称を**ISG（Incremental Static Generation）**といいます。

# SSGの問題点
SSGは前述のとおりビルド時にデータを取得してページに表示します。

ここで問題が発生します。

**ビルド以降、データが更新されたらページに反映されない**のです。
（例：一覧データが増えても反映されない）

外部データの取得をクライアント側で行うと、結局CSRによって成り立っているのと同じ。

なるべくSSGを使いたいが、規模が大きくなるほど使い勝手が悪くなる・・

そこでv9.4より登場したのがISRです！

# ISR（Incremental Static Regeneration）
直訳すると"段階的静的**再**生成"とあるように、

ISRは**クライアント側のリクエストに対しビルド時に生成された静的ページを返し、かつバックグラウンドで一定期間ごとに静的ページの再生成をサーバー側で行います。**

これにより、SSGの問題点に対応できます！

## getStaticProps関数にrevalidateを追加

具体的にコードで見ます。

```javascript:index.jsx
export async function getStaticProps(context) {
 const postId = context.params.id
 const post = postIDによるpostデータ取得処理
 return {
   props: { postId, post },
   revalidate: 30, // ここを追加
 }
}
```

getStaticProps 関数から return するオブジェクトの中で、**revalidate**というキーに対して秒数を指定します。ここでは30秒を指定しています。

つまり30秒経過後クライアント側からリクエストがあったら、
**クライアントには既に生成されたページを見せつつ、バックグラウンドでデータの再取得及び再レンダリングを行いページを再生成し、次のリクエストに対しては再生成されたページを返します。**

これによって、データの変化も反映することができます。


# おわりに
最近はもっぱらNext.jsでの開発です。
ふだんはNotionにまとめてますが、第三者に見える形でのアウトプットも大切ですね。
なにか内容に誤りがあればご指摘ください。