Next.js 資料擷取
規則
- 在伺服器元件中使用 async/await 擷取資料。不要使用
useEffect 處理初始資料。
fetch() 在 App Router 中預設是快取的,除非加上 { cache: 'no-store' } 或 next: { revalidate } 參數。請務必清楚你要哪一種行為。
- 使用
Promise.all 平行化獨立的請求。只有依賴性的請求才依序執行。
- 將較慢的區塊包在
<Suspense fallback> 加上 loading.tsx 中以實現串流。
- 使用
next: { tags: ['posts'] } 搭配 revalidateTag('posts') 進行隨選失效。
- 僅在互動式/過濾式 UI 中才使用客戶端擷取(SWR/React Query)——不要用於首次畫面呈現。
範例模式
async function getPosts() {
const res = await fetch('https://api.example.com/posts', {
next: { revalidate: 60 },
});
if (!res.ok) throw new Error('無法擷取文章');
return res.json();
}
async function getInbox(userId: string) {
const res = await fetch(`https://api.example.com/inbox/${userId}`, {
cache: 'no-store',
});
return res.json();
}
export default async function Dashboard() {
const [user, posts] = await Promise.all([getUser(), getPosts()]);
return <View user={user} posts={posts} />;
}
import { Suspense } from 'react';
export default function Page() {
return (
<div>
<FastHeader />
<Suspense fallback={<CommentsSkeleton />}>
<SlowComments />
</Suspense>
</div>
);
}
import { revalidateTag } from 'next/cache';
export async function POST(req: Request) {
const { tag, secret } = await req.json();
if (secret !== process.env.REVALIDATE_SECRET)
return Response.json({ ok: false }, { status: 401 });
revalidateTag(tag);
return Response.json({ ok: true });
}
檢查清單