理解 Next.js 缓存(第5部分)

发布: (2026年3月28日 GMT+8 20:24)
5 分钟阅读
原文: Dev.to

Source: Dev.to

面包店类比(API 数据 vs 页面)

把你的 Next.js 应用想象成一家面包店。

  • API 数据(数据缓存) 就是从数据库或外部 API 获取的原料(面粉、糖、鸡蛋)。
  • 页面(完整路由缓存) 就是摆在橱窗里的成品蛋糕。

Next.js 不仅缓存生成好的 HTML(蛋糕),还会缓存原始的 JSON(原料)。这意味着如果 50 位用户在同一时刻访问你的网站,Next.js 不会对数据库发起 50 次查询——它会使用缓存的原料立即为所有人提供服务。

四层缓存

最常让人困惑的点是用户点击刷新按钮时会发生什么。下面用厨房的比喻展示 Next.js 的四层缓存。

1. 请求记忆化(台面/剪贴板)

如果同一页面上的三个不同 React 组件都调用 fetch('/api/user'),Next.js 会去重请求:只发起一次网络请求并共享结果。

注意: 台面/剪贴板会在每一次页面渲染后被清空。

2. 路由缓存(顾客的盘子)

当用户在应用中导航时,Next.js 会把 React Server Component 的负载存入浏览器内存。这使得点击 返回 按钮时几乎是瞬间完成。

注意: 该缓存不会在硬刷新后保留;刷新会清空浏览器的内存(洗掉盘子)。

3. 数据缓存(储藏室)

Next.js 会在 多个 用户会话之间存储从数据库返回的原始 JSON 数据。

注意: 这在刷新后仍然存在。当页面刷新时,浏览器会向服务器请求新数据,但服务器会直接从储藏室取出同一份缓存数据。这也是刷新往往不能“修复”陈旧数据的原因。

4. 完整路由缓存(橱窗)

Next.js 将缓存的数据和你的组件在构建时渲染成纯静态 HTML。

注意: 只要底层的 数据缓存 未被显式失效,这个缓存会在刷新后仍然生效,因为它会一直提供预渲染的 HTML 文件。

控制缓存

缓存对性能非常有利,但动态应用需要动态数据。下面介绍如何让 Next.js 丢弃陈旧的原料。

1. 完全关闭缓存(不缓存)

如果某段数据经常变化(例如实时股票行情或银行账户余额),可以告诉 Next.js 完全不缓存 fetch 请求:

// 每一次请求都重新获取
const res = await fetch('https://api.example.com/data', {
  cache: 'no-store',
});

2. 基于时间的重新验证(Stale‑While‑Revalidate)

让 Next.js 在一定时间内保留缓存,之后在后台获取新数据:

// 每 3600 秒(1 小时)重新验证一次数据
const res = await fetch('https://api.example.com/data', {
  next: { revalidate: 3600 },
});

3. 按需重新验证(“失效”按钮)

当用户提交表单(例如更新个人资料)时,需要立即清除该页面的缓存。可以在 Server Action 中这样做:

'use server';
import { revalidatePath } from 'next/cache';

export async function updateProfile(formData) {
  await db.user.update(formData);

  // 告诉 Next.js 丢弃该路由的缓存 HTML 和数据
  revalidatePath('/profile');
}

大结局

在这五篇文章中,我们从“新鲜 vs 陈旧”的理论出发,逐步掌握了 HTTP 头、调教 React‑Query/Redux 客户端状态,最终征服了 Next.js 的服务器缓存。

缓存不再只是后端的性能优化——它是前端用户体验的核心跳动。掌握它,你就能构建出即刻响应且节省服务器成本的应用。

现在,去构建一些快速的东西吧。

0 浏览
Back to Blog

相关文章

阅读更多 »