01 · NOTES / WebGIS 开发
第 22 节 · 数据获取(服务端 fetch)
2026 年 9 月 1 日
第 22 节 · 数据获取(服务端 fetch)
📌 版本信息:Next.js 15.x(2026-08-29 核对) 📚 来源:Next.js · Fetching Data | 升级:缓存与再验证 ▶️ 配套练习:
examples/22-列表与详情页/
一、这一节的目标
- 掌握服务端组件里
await fetch——组件可以是 async 的 - 理解"取数发生在服务器",浏览器拿到的已是成品
- 初识 fetch 缓存(默认缓存与 revalidate 一句话版,第 26 节深讲)
- 完成列表 + 详情页(服务端取数版)
二、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:
- 读
lib/posts.js:模拟"远端数据库"(setTimeout 延迟) - 完成 5 个 TODO:列表页 async 化、详情页按 params 取数 + notFound、详情页加
generateStaticParams把两篇文章转成 SSG(build 输出里看 ● 标记)、详情页 fetch 外部真数据(Open-Meteo 当"相关天气"演示 revalidate: 3600)、列表页加批量Promise.all取"每篇的评论数"占位
通关标准:
- 进入
/posts时先见 loading 骨架再出内容(服务端取数 + loading.js 配合) -
npm run build输出能看到详情页被静态化(●) - 能说出"async 组件只能在服务端"的原因
五、自测题
- 服务端组件为什么能
await?客户端组件为什么不能? - 服务端取数的密钥安全性体现在哪?
revalidate: 3600的语义?- 交互组件需要数据的三条路?
- async 页面抛错被谁接住?
参考答案
- 服务端组件在 Node 里渲染(await 自然合法);客户端组件要在浏览器跑,async 组件无法配合交互与 hooks 机制。
- 环境变量只在服务端读取,不会打进客户端包——API key 可安全使用。
- 该请求结果缓存 1 小时,期内访问直接复用缓存(到期后后台重新取,ISR 语义)。
- 父级服务端组件取好传 props;Route Handler 中转(客户端 fetch 自己的 /api);客户端状态库直接请求第三方(需 CORS)。
- 该段的 error.js(没有则向上冒泡到最近的 error 边界,最终全局 error)。
六、下一步
数据能"在服务端就位" → 第 23 节:服务端/客户端组件,把"use client"的边界一次划清。
TAGSweb