缓存策略

2026年9月6日

Next 默认能缓存的都缓存:路由预渲染、fetch 结果复用。开发时每次刷新都像「最新」,next build && next start 之后可能发现随机图片冻住了——因为这条路由被当成静态页了。

先分清你有没有开 cacheComponents


未开启时

配置里关掉或不写:

const nextConfig = {
  cacheComponents: false,
};
ts

构建日志里常见:

  • 静态预渲染
  • ƒ 动态,每次请求现算

下面这个页面开发看着会变,生产构建后可能一直同一张图:

export default async function Page() {
  const res = await fetch("https://example.com/random.json");
  const data = await res.json();
  return <img src={data.url} alt="" />;
}
tsx

退出缓存有几条路,选一条就够。

1. 整页 revalidate

export const revalidate = 5; // 秒;0 表示不缓存
tsx

过期后下一次请求触发重新生成。

2. 强制动态

export const dynamic = "force-dynamic";
tsx

这条路由不当静态页。开了 Cache Components 之后,默认已经偏动态,一般不用再写。

3. 单次 fetch 不存

await fetch(url, { cache: "no-store" });
tsx

4. 碰动态 API

用了下面任意一个,路由会按动态处理:

  • cookies()
  • headers()
  • connection()
  • 读请求上的 searchParams
  • fetch(..., { cache: "no-store" })
import { connection } from "next/server";

export default async function Page() {
  await connection();
  const res = await fetch("https://example.com/random.json");
  // ...
}
tsx

开启 Cache Components 之后

cacheComponents: true 时,组件默认按动态内容处理,动态部分用 Suspense 包起来。构建日志里可能多一个:

  • 部分预渲染:外壳静态,洞里的内容请求时再流式补
import { Suspense } from "react";

async function RandomImage() {
  const res = await fetch("https://example.com/random.json");
  const data = await res.json();
  return <img src={data.url} alt="" />;
}

export default function Page() {
  return (
    <div>
      <h1>首页</h1>
      <Suspense fallback={<p>Loading…</p>}>
        <RandomImage />
      </Suspense>
    </div>
  );
}
tsx

要缓存动态结果,回到上一篇的 'use cache' + cacheLife,不要混用旧的 export const dynamic 当主开关。


怎么选

目标未开 Cache Components已开
尽量静态什么都别标别读 cookie / 别乱 fetch
隔一会儿更新revalidate = nuse cache + cacheLife
每次都新force-dynamicno-storeSuspense + 动态 API

下一篇开始内置组件:next/image


参考文档