📘

【Next.js】prefetch 時に fetch がどこまで動くのかを検証した

2024/10/29に公開

モチベーション

Next.js の App Router で

  • 全ページに dynamic rendering を強制している
  • loading.js を一つも配置していない

という状況のとき、prefetch(プリフェッチ)で fetch によるデータの取得が行われるのかの理解が曖昧だったため改めて検証した。

環境

  • Next.js v15.0.1 App Router

検証に使用したソースコードは下記に配置した。

https://gitlab.com/k1350/nextjs-15-prefetch-test

Link コンポーネントの prefetch 以外の設定はすべて v15.0.1 のデフォルト設定で検証した。

検証

検証パターンについて

今回の検証では Link コンポーネントの prefetch を対象とする。

https://nextjs.org/docs/app/api-reference/components/link#prefetch

prefetch が取り得る値は

  • null
  • true
  • false

の三種類だが、false の場合は prefetch が発生しないので除外する。

また prefetch = null のときの説明は

Prefetch behavior depends on whether the route is static or dynamic. For static routes, the full route will be prefetched (including all its data). For dynamic routes, the partial route down to the nearest segment with a loading.js boundary will be prefetched.

なのだが、Route Segment Config で dynamic を指定すれば static routes にも dynamic rendering を強制することが可能である。
今回の検証中、実際に dynamic = "force-dynamic" を指定することにより、dynamic routes かどうかではなく dynamic rendering かどうかによって挙動が変わるということを確認できたので、static rendering / dynamic rendering という表現で話を進める。

Dynamic rendering の場合は loading.js ファイルの配置によって挙動が変わる。
loading.js がある場合の挙動は説明からわかるが、loading.js が一つも無かったら一切 fetch が動かないという理解でいいのか? という点が気になっているため、今回は loading.js の有無でパターン分けする。

まとめると今回検証するパターンは下記である。

prefetch = null prefetch = true
static rendering ? ?
dynamic rendering(loading.js あり) ? ?
dynamic rendering(loading.js なし) ? ?

検証結果

まず前提となるが、Client Component の useEffect 内での fetch は、ページを実際に表示したときに初めて行われる。

従って、以下はすべて Server Component の話である。
また Suspense で囲っているかどうかが影響するかも検証したが、影響しなかった。よって以下は Server Components 内での fetch すべてに当てはまる。

Static rendering

ビルド時にすべてのセグメントで fetch によるデータ取得が行われる。
Prefetch 時に改めてデータ取得が行われることはない。

Dynamic rendering(prefetch = true)

loading.js の有無によらず、prefetch 時にすべてのセグメントで fetch による取得が行われる。

Dynamic rendering(prefetch = null)

下記のようなファイル配置なら prefetch 時に layout.tsx 内の fetch のみ実行される。

app
|-dynamic
  |-layout.tsx
  |-[id]
    |-loading.tsx
    |-page.tsx

一方下記のように loading.js が一つも配置されていない場合、prefetch 時に fetch によるデータ取得は一切行われない。

app
|-dynamic
  |-layout.tsx
  |-[id]
    |-page.tsx

通常、loading.js は Suspense とセットで使用することが多いと思う。
しかし prefetch がどのセグメントまで行われるかに関しては loading.js がどこに配置されているかで決まり、Suspense が使われているかどうか(=loading.tsx の中身が表示され得るかどうか)は関係ない。

まとめ

prefetch = null prefetch = true
static rendering ビルド時に全部 ビルド時に全部
dynamic rendering(loading.js あり) loading.js が最初に配置されているセグメントの親まで 全部
dynamic rendering(loading.js なし) fetch しない 全部

結論としては、

  • 全ページに dynamic rendering を強制している
  • loading.js を一つも配置していない

というケースでは prefetch 時に fetch によるデータ取得は一切行われない。

もしデータ取得をしてほしい場合、Suspense を使用していなくても、適切なセグメントに loading.js を配置する必要がある。

chot Inc. tech blog

Discussion