第 07 节:服务器上取数据:async、fetch、loading
本节 objectives:
- 能读懂
async function和await fetch(...)的基本形状。- 能在 Server Component 页面中获取并渲染远程数据。
- 能添加一个
loading.tsx作为加载占位。先修:会写路由、列表、Server/Client Component 基本判断 | 上一节 << 06 | 下一节 08 >>
数据可以先在服务器上准备好
浏览器当然可以取数据,但 Next.js 的 App Router 允许你在 Server Component 里直接写异步取数代码。官方数据获取文档展示了在组件中使用 fetch 获取数据的模式1。这会让页面代码更接近「拿数据,渲染页面」的顺序。
你只需要先掌握三个词:async 表示函数里可以等待异步结果;await 表示等这个 Promise 完成;fetch 是 Web 平台用于发网络请求的 API23。
讲解
async 让函数可以等待。
MDN 把 async function 描述为会返回 Promise 的异步函数2。你现在不必完全理解 Promise,先记住:看到 await,外层函数通常要写 async。
fetch 拿到的是响应,不是直接的数据。
常见写法是:
第一行拿响应,第二行把响应体解析成 JavaScript 数据。MDN 的 fetch 指南也把请求、响应和解析分开讲3。
Server Component 可以直接 await。
在 App Router 中,页面组件可以写成 export default async function Page() { ... },然后等待数据1。这和 Client Component 里用 useEffect 不是同一条路。
loading.tsx 是同一路由的加载状态。
当某个路由段在准备内容时,loading.tsx 可以显示占位界面。它和 page.tsx 放在同一个路由文件夹里,服务同一段页面体验4。
跟我做一遍(worked example)
目标:创建 /posts 页面,从一个示例接口读取博客标题。
- 新建
app/posts/page.tsx:
- 新建
app/posts/loading.tsx:
为什么这样写:
getPosts把取数逻辑集中起来。response.ok先做最小错误判断。PostsPage是 async Server Component。- 取回来的数组继续用上一节学过的
map渲染。
换你补全(faded example)
下面要读取同一个接口,只显示前三篇文章。补全 async、await 和 map 的关键位置。
参考答案:
关键判断点:等待网络请求和等待 getPosts 都要 await;数组转 JSX 仍然用 map。
小结 + 通向下一节
你已经能在服务器上取数据并显示列表。最后一节把路由、组件、交互和取数收束成一个小站,再用构建命令检查它是否能进入下一阶段。
Footnotes
-
Next.js Fetching Data — https://nextjs.org/docs/app/getting-started/fetching-data ↩ ↩2
-
MDN: async function — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function ↩ ↩2
-
MDN: Using the Fetch API — https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch ↩ ↩2
-
Next.js Layouts and Pages — https://nextjs.org/docs/app/getting-started/layouts-and-pages ↩
练习
Level 1:标出数据流。
做法:把 worked example 的代码复制到笔记,用数字标出顺序:请求接口、检查响应、解析 JSON、渲染列表。
提示 1
先找所有 await。
提示 2
再看数据变量从 response 变成 posts。
Level 2:加一个空状态。
做法:在 PostsPage 里,如果 posts.length === 0,显示「暂时没有文章」。
看参考答案
常见错误剖析:把 await fetch(...) 写进 Client Component 的点击事件里,然后又期待页面首次打开时就有数据。服务器取数和浏览器交互是两种路径;这一节练的是页面加载前在服务器准备数据。