【Next.js】キャッシュまとめ

## キャッシュの種類

Next.jsのキャッシュは以下の4種類。

- Request Memoization
- Data Cache
- Full Route Cache
- Router Cache

| キャッシュの種類 | 保存先 | 存続期間 | キャッシュ方法 | 再検証方法 | オプトアウト方法 |
| --- | --- | --- | --- | --- | --- |
| Request Memoization | サーバー | 1回のレンダリング中のみ | RSCにGETの `fetch` または React の `cache`| レンダリング完了時に削除 | `fetch` の引数に `signal` を渡す |
| Data Cache | サーバー | 再検証やオプトアウトしない限り、複数のリクエストやユーザーにわたって永続的。再デプロイしても削除されない | `fetch` を使用してデータをリクエスト | Time-based Revalidation または On-demand Revalidation | `fetch` に `cache: 'no-store'` を渡す または セグメント構成オプションを使用 |
| Full Route Cache | サーバー | 複数のリクエストやユーザーにわたって永続的。アプリケーションをデプロイする際に削除 | 静的レンダリングが使用されるようにする | Data Cache を再検証する または 再デプロイする | Data Cache をオプトアウトする または 動的関数を使用する |
| Router Cache | ブラウザの一時メモリ | ナビゲーション全体で持続。ページを更新すると全ての Router Cache が削除。Prefetch の方法により30秒または5分後にセグメント単位で削除 | 特別なことは不要。デフォルトでキャッシュされる | サーバーアクション内で `revalidatePath`, `revaliadteTag`, `cookies.set`, `cookies.delete` を実行 または `router.refresh`を実行 | できない |

## Request Memoization

レンダリング中にサーバーコンポーネントで行われるすべての同一リクエストをキャッシュする React の機能。

これにより、同じページの複数コンポーネントで同一のデータが必要な場合に、　`fetch` を複数回記述しても実際に実行されるのは1回のみとなる。

### キャッシュの保存先

サーバーに保存される。

### キャッシュの存続期間

レンダリング完了時に削除。
つまり、1回のレンダリング中のみ有効。

### キャッシュする方法

サーバーコンポーネントにGETの `fetch` を記述する。
`fetch` 以外には React の `cache` を使用する。

https://react.dev/reference/react/cache#noun-labs-1201738-(2)

### 再検証する方法

レンダリング完了時に削除されるため、わざわざ再検証する必要はない。

### オプトアウトする方法

`fetch` の引数に `signal` を渡す。

```js
const { signal } = new AbortController()
fetch(url, { signal })
```

## Data Cache

Request Memoization と似ているが、複数のリクエストやユーザーに渡って永続的なキャッシュ。

### キャッシュの保存先

サーバーに保存される。

### キャッシュの存続期間

再検証やオプトアウトしない限り、複数のリクエストやユーザーにわたって永続的。
新しいバージョンをデプロイしても保持される。

### キャッシュする方法

サーバーコンポーネントで `fetch` を使用してデータをリクエストする。

### 再検証する方法

再検証する方法は以下の２つ。

- Time-based Revalidation （時間ベースの再検証）
- On-demand Revalidation （オンデマンド再検証）

#### Time-based Revalidation

以下のように `fetch` の引数に `next: { revalidate: 時間(秒) }` を渡す。

```js
fetch('https://...', { next: { revalidate: 3600 } })
```

上記の場合には1時間ごとに再検証する。
ただし、1時間経過して最初のリクエストにはキャッシュを返す。同時に再検証し、次のリクエストから再検証後のデータを返却する。

#### On-demand Revalidation

[revalidatePath](https://nextjs.org/docs/app/building-your-application/caching#revalidatepath) や [revalidateTag](https://nextjs.org/docs/app/building-your-application/caching#fetch-optionsnexttags-and-revalidatetag) を使用して任意のタイミングで再検証する。

### オプトアウトする方法

以下のいずれかの方法でオプトアウトできる。

#### `fetch` に `cache: 'no-store'` を渡す

```js
fetch(`https://...`, { cache: 'no-store' })
```

#### セグメント構成オプションを使用する

特定のルートセグメント全体のキャッシュをオプトアウトする。

```js
export const dynamic = 'force-dynamic'
```

```js
export const revalidate = 0
```

https://nextjs.org/docs/app/building-your-application/caching#segment-config-options

## Full Route Cache

ビルド時や再検証時に静的にレンダリングされたルートのレンダリング結果をキャッシュする。

### キャッシュの保存先

サーバーに保存される。

### キャッシュの存続期間

複数のリクエストやユーザーにわたって永続的。
アプリケーションをデプロイする際に削除される。

### キャッシュする方法

静的レンダリングが使用されるようにする。

https://nextjs.org/docs/app/building-your-application/rendering/server-components#static-rendering-default

### 再検証する方法

- Data Cache を再検証する
- 再デプロイする

### オプトアウトする方法

- Data Cache をオプトアウトする
- [動的関数](https://nextjs.org/docs/app/building-your-application/caching#dynamic-functions)を使用する

## Router Cache

ユーザーが訪問したページのキャッシュ。

ユーザーがそのページに戻ってきたときにキャッシュされたバージョンを使用し、サーバーにリクエストしない。

### キャッシュの保存先

ブラウザの一時メモリに保存される。

### キャッシュの存続期間

キャッシュはナビゲーション全体で持続する。
ページを更新すると全ての Router Cache が削除される。

また、以下の時間経過するとセグメント単位で自動削除。

- Default Prefetching （`prefetch={null}` または 指定なし)：30秒
- Full Prefetching　（`prefetch={true}` または `router.prefetch`)：5分

### キャッシュする方法

特別なことは不要。デフォルトでキャッシュされる。

### 再検証する方法

サーバーアクション内で以下のいずれかを実行する。

- `revalidatePath`
- `revaliadteTag`
- `cookies.set`
- `cookies.delete`

または、`router.refresh`を実行する。

### オプトアウト

できない。

## 参考

https://nextjs.org/docs/app/building-your-application/caching

https://blog.webdevsimplified.com/2024-01/next-js-app-router-cache/