資料抓取
因為 Server Component 本來就只在伺服器端執行,抓資料不需要 useEffect 或額外的資料層套件,直接把元件宣告成 async 函式、用 await 抓資料即可。
基本寫法
app/posts/page.tsx
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() {
const posts = await getPosts();
return (
<ul>
{posts.map((post: { id: string; title: string }) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Next.js 擴充了原生 fetch,加上快取與重新驗證選項;細節見 快取與重新驗證。資料庫查詢(例如用 Prisma)也可以直接寫在 Server Component 裡,原理相同。
並行抓取 vs. 循序抓取
多個資料來源互不相依時,先各自建立 Promise、再一起 await,可以平行進行、縮短總等待時間:
async function getUser(id: string) { /* ... */ }
async function getPosts(id: string) { /* ... */ }
export default async function ProfilePage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
// 兩個請求同時發出,而不是一個等完才發下一個
const userPromise = getUser(id);
const postsPromise = getPosts(id);
const [user, posts] = await Promise.all([userPromise, postsPromise]);
return (
<>
<h1>{user.name}</h1>
<PostList posts={posts} />
</>
);
}
若後一個請求的參數依賴前一個請求的結果,才需要循序 await;否則預設應該讓互不相依的請求並行。
用 loading.tsx 搭配 Suspense 做串流
資料抓取需要時間時,在同一路由層級加上 loading.tsx,Next.js 會自動用 React Suspense 包住該路由,先顯示載入畫面、資料就緒後再換成實際內容,使用者不會看到整頁空白:
想要更精細地控制(例如頁面裡只有某個區塊要顯示載入中,其餘部分先顯示),可以直接用 <Suspense> 包住個別的 async 元件。
推薦影音
在 Server Components 抓資料
簡述:Codevolution 這支影片示範如何在 Server Component 裡呼叫 API、處理 loading 與錯誤狀態,內容與上面範例的寫法一致,適合想看實際操作過程的學習者。
下一步
資料抓到之後,Next.js 還會依快取設定決定這個結果能不能重複使用、要不要定期更新,詳見 快取與重新驗證。