跳到主要内容

缓存

概述

概述

MechanismWhatWherePurposeDuration
Request MemoizationReturn values of functionsServerRe-use data in a React Component treePer-request lifecycle
Data CacheDataServerStore data across user requests and deploymentsPersistent (can be revalidated)
Full Route CacheHTML and RSC payloadServerReduce rendering cost and improve performancePersistent (can be revalidated)
Router CacheRSC PayloadClientReduce server requests on navigationUser session or time-based

概述

动态渲染和静态渲染

  • 静态路由默认被缓存;
  • 动态路由在请求时渲染,不会进行 Router Cache 以外的缓存;

动态渲染和静态渲染

工作流程

服务器渲染
  • React 将 RSC 转换成 RSC Payload;
  • next 将 RSC Payload 和对应 js 转换为 html;
Full Route Cache
  • next 在服务器缓存对应路由的 RSC Payload 和其渲染结果 HTML;
react hydration
  • 立刻接受预先渲染的无交互逻辑的 HTML,仅限于首屏加载;
  • 接受 RSC payload,构建组件树,并更新 DOM;
  • next 水合 client component 和 js 代码,使其具有交互性;
Router Cache
  • 客户端缓存 RSC Payload;
Subsequent Navigation
  • next 检查对应路由是否具有 Router Cache;
    • 若已缓存,跳过请求返回 RSC Payload;
    • 若未缓存,向服务器发送请求,并将请求结果缓存至 Route Cache;

Request Memoization

memoize

  • react 行为;
  • react 拓展 fetch API,自动缓存具有相同 URL 和 option 的请求;
  • 多个组件同时调用相同请求只需请求一次;
async function getItem() {
// The `fetch` function is automatically memoized and the result
// is cached
const res = await fetch("https://.../item/1");
return res.json();
}

// This function is called twice, but only executed the first time
const item = await getItem(); // cache MISS
// The second call could be anywhere in your route
const item = await getItem(); // cache HIT

工作机制

  • Request Memoization 作用于同一次渲染流程;
  • 客户端第一次发送请求,服务器执行函数并缓存数据至内存;
  • 客户端再次发送请求,直接从缓存中获取数据;
  • 该次渲染完毕,清空内存中的缓存数据;

工作机制

应用范围

  • 只作用于 fetch 的 GET 请求;
  • 只作用于 React Component tree;

生命周期

  • 单次渲染流程;
  • 可通过选择退出清空缓存;
    • 使用 AbortController;
const { signal } = new AbortController();
fetch(url, { signal });

Data Cache

Data Cache

  • next 行为;
  • next 拓展 fetch API,缓存请求结果数据;
  • 任何类型请求均被缓存;

工作机制

  • 客户端发送请求,next 健在对应数据是否缓存;
    • 若未缓存,服务期执行代码返回数据,持久化缓存至 Data Cache,并对其 memoize;
    • 若已缓存,直接返回数据,并对其 memoize;
  • 对于 next config 中设置 { cache: 'no-store' } 的数据;
    • 服务期执行代码返回数据,并对其 memoize;

工作机制

生命周期

  • 持久化存储;
  • 可通过重新验证或者选择退出清空缓存;

选择退出

  • 设置 cache: 'no-store' 选项;
// Opt out of caching for an individual `fetch` request
fetch(`https://...`, { cache: "no-store" });

Full Route Cache

Full Route Cache

  • next 在构建时自动缓存 route 请求结果;
  • next 在服务器缓存对应路由的 RSC Payload 和其渲染结果 HTML;

生命周期

  • 持久化存储;
  • 可通过清空 Data Cache,使用动态函数,重新部署清空缓存;

Route Cache

Route Cache

  • next 行为;
  • 将 RSC Payload 缓存至客户端内存中;
  • 提高路由导航性能;

工作机制

  • next 检查对应路由是否具有 Router Cache;
    • 若已缓存,跳过请求,直接返回缓存 RSC Payload;
    • 若未缓存,向服务器发送请求,并将请求对应 RSC Payload 缓存至 Route Cache;

工作机制

生命周期

  • 用户会话期间;
  • 固定时间间隔自动清空;
    • 动态渲染:30s;
    • 静态渲染:5min;
  • 可通过重新验证,使用动态函数清空缓存;

prefetch

  • 使用 prefetch={true} 或 router.prefetch;
  • 强制缓存 5min,无论静态路由还是动态路由;

其他

react 原生数据缓存

  • 使用 react 的 cache api;
  • 实验性行为,只能应用于 ssr,以后才学;
// util.ts
import { cache } from "react";
export const getItem = cache(async (id: string) => {
const item = await db.item.findUnique({ id });
return item;
});

// page.ts
import { getItem } from "@/utils/get-item";
export const revalidate = 3600; // revalidate the data at most every hour
export default async function Page({
params: { id },
}: {
params: { id: string };
}) {
const item = await getItem(id);
// ...
}

数据验证

数据验证
  • 清除数据缓存,重新获取数据;
验证策略
  • 基于时间自动验证数据;
  • 手动重新验证数据;
    • 使用 revalidateTag() api;
      • 定义 next config 中的 tag 标签;
      • 使用 revalidateTag() 基于 tag 标签验证
    • 使用 revalidatePath() api;
// 基于时间自动验证数据 (秒)
fetch("https://...", { next: { revalidate: 3600 } });

// 使用 revalidatePath() api
("use server");
import { revalidatePath } from "next/cache";
export async function createPost() {
try {
// ...
} catch (error) {
// ...
}
revalidatePath("/posts");
}

// 使用 revalidateTag() api
export default async function Page() {
const res = await fetch("https://...", { next: { tags: ["collection"] } });
const data = await res.json();
// ...
}
("use server");
import { revalidateTag } from "next/cache";
export default async function action() {
revalidateTag("collection");
}

缓存交互

  • Data Cache 的清空会作用于 Full Route Cache;
  • Full Route Cache 的清空不会作用于 Data Cache;
  • Data Cache 和 Route Cache;
    • Route Handler 中 Data Cache 的清空不会作用于 Route Cache;
      • 因为无法判断具体的路由片段;
    • Server Action 中 Data Cache 的清空会作用于 Route Cache;

API

APIRouter CacheFull Route CacheData CacheReact Cache
Link prefetchCache
router.prefetchCache
router.refreshRevalidate
fetchCacheCache
fetch options.cacheCache or Opt out
fetch options.next.revalidateRevalidateRevalidate
fetch options.next.tagsCacheCache
revalidateTagRevalidate (Server Action)RevalidateRevalidate
revalidatePathRevalidate (Server Action)RevalidateRevalidate
const revalidateRevalidate or Opt outRevalidate or Opt out
const dynamicCache or Opt outCache or Opt out
cookiesRevalidate (Server Action)Opt out
headers, useSearchParams, searchParamsOpt out
generateStaticParamsCache
React.cacheCache
unstable_cache