返回笔记列表
01 · NOTES / WebGIS 开发

第 22 节 · 数据获取(服务端 fetch)

2026 年 9 月 1 日

第 22 节 · 数据获取(服务端 fetch)

📌 版本信息:Next.js 15.x(2026-08-29 核对) 📚 来源:Next.js · Fetching Data升级:缓存与再验证 ▶️ 配套练习:examples/22-列表与详情页/

一、这一节的目标

  1. 掌握服务端组件里 await fetch——组件可以是 async 的
  2. 理解"取数发生在服务器",浏览器拿到的已是成品
  3. 初识 fetch 缓存(默认缓存与 revalidate 一句话版,第 26 节深讲)
  4. 完成列表 + 详情页(服务端取数版)

二、Async 组件:Next 给 React 的礼物

第 17 节说过 async 函数返回 Promise 不能直接当组件——Next 的服务端组件例外:在服务器上渲染,可以真正 await:

// app/posts/page.js —— 服务端组件(默认就是)
async function getPosts() {
  const res = await fetch('https://api.example.com/posts');
  if (!res.ok) throw new Error('加载失败');
  return res.json();
}

export default async function PostsPage() {          // ← async 组件!
  const posts = await getPosts();                     // ← 直接 await,无需 useEffect!
  return <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>;
}

与 React+Vite 取数的三点对比

SPA(useEffect + fetch) Next 服务端组件
取数时机 浏览器渲染后(白屏等待) 服务器渲染时(用户拿到的就是成品)
代码位置 组件里 + 三态样板 组件里直接 await(loading.js 接管加载态)
密钥安全 不能放(会打进包) 可以放(.env 只在服务端读)

⚠️ 交互组件里不能 async"use client" 组件不能用 async/await 取数——需要数据就由父级服务端组件取好用 props 传下来,或客户端用 SWR/状态库请求(第 23 节边界)。


三、fetch 缓存一句话版(第 26 节展开)

fetch(url, { next: { revalidate: 3600 } });  // 缓存 1 小时(ISR 味道:期内请求直接用缓存)
fetch(url, { cache: 'no-store' });           // 每次请求都重新取(实时数据)
fetch(url);                                  // Next 15 默认:不缓存(按需 revalidate)

现阶段只需记住:默认行为够用;内容变化慢的数据加 revalidate 提速;实时数据 no-store


四、动手跟练:22 · 列表与详情页

配套文件夹:22-列表与详情页/npm i && npm run dev

结构/posts 列表(服务端 async 取数)→ /posts/[slug] 详情(按 slug 再取)。数据源用 lib/posts.js(内含 1.5 秒人工延迟——让 loading.js 有戏份)。

步骤与 TODO:

  1. lib/posts.js:模拟"远端数据库"(setTimeout 延迟)
  2. 完成 5 个 TODO:列表页 async 化、详情页按 params 取数 + notFound、详情页加 generateStaticParams 把两篇文章转成 SSG(build 输出里看 ● 标记)、详情页 fetch 外部真数据(Open-Meteo 当"相关天气"演示 revalidate: 3600)、列表页加批量 Promise.all 取"每篇的评论数"占位

通关标准:

  • 进入 /posts 时先见 loading 骨架再出内容(服务端取数 + loading.js 配合)
  • npm run build 输出能看到详情页被静态化(●)
  • 能说出"async 组件只能在服务端"的原因

五、自测题

  1. 服务端组件为什么能 await?客户端组件为什么不能?
  2. 服务端取数的密钥安全性体现在哪?
  3. revalidate: 3600 的语义?
  4. 交互组件需要数据的三条路?
  5. async 页面抛错被谁接住?

参考答案

  1. 服务端组件在 Node 里渲染(await 自然合法);客户端组件要在浏览器跑,async 组件无法配合交互与 hooks 机制。
  2. 环境变量只在服务端读取,不会打进客户端包——API key 可安全使用。
  3. 该请求结果缓存 1 小时,期内访问直接复用缓存(到期后后台重新取,ISR 语义)。
  4. 父级服务端组件取好传 props;Route Handler 中转(客户端 fetch 自己的 /api);客户端状态库直接请求第三方(需 CORS)。
  5. 该段的 error.js(没有则向上冒泡到最近的 error 边界,最终全局 error)。

六、下一步

数据能"在服务端就位" → 第 23 节:服务端/客户端组件,把"use client"的边界一次划清。

TAGSweb