TL;DR

Next.js は、静的データをキャッシュするために fetch を拡張している。Next.js 14 まではデフォルトでキャッシュし、Next.js 15 からはデフォルトでキャッシュしなくなった。

なぜ必要か

静的データとは、更新頻度が低く参照頻度が高い、誰もが共有できるデータである(商品概要、ブログ記事、ニュース記事など)。動的データとは、更新頻度が高く、アクセスできる人が限られたデータである(閲覧履歴、商品の在庫数、ログインユーザの情報など)。静的データをキャッシュすると、Web API サーバへのアクセス回数を減らせる。データ取得の遅延も減り、画面の表示も速くなる。

仕組み

Next.js 14 まで

fetch はデフォルトで静的データの取得として扱われ、結果はキャッシュされる(Data Cache)。キャッシュしたデータは .next/cache/fetch-cache に保存される。動的データとして扱いたいときは、第 2 引数に { cache: "no-store" } を渡す。

fetch("https://...", { cache: "no-store" })

Next.js 15 から

デフォルトでキャッシュされなくなった。キャッシュするには、第 2 引数に { cache: "force-cache" } を渡す。

注意点

拡張元の fetch と同じく、400 以上のステータスコードが返っても Promise は reject されない。

fetch() のプロミスは、サーバーがエラーを示す HTTP ステータスコード(404、504 など)を返しても拒否されません。

代わりに、 then() ハンドラーで Response.ok や Response.status プロパティをチェックする必要があります。

次のように Response.ok を確かめる handleSucceed を then に渡せばよい。

export class FetchError extends Error {
  status: number
  constructor(message: string, status: number) {
    super(message)
    this.status = status
  }
}
 
export const handleSucceed = async (res: Response) => {
  const data = await res.json()
  if (!res.ok) {
    throw new FetchError(res.statusText, res.status)
  }
  return data
}
fetch("...").then(handleSucceed)

関連

出典