Sanity x Next.js 撈取 Post 資料踩坑紀錄

2025/08/19

最近在做 Sanity + Next.js 專案時,遇到一個奇怪的問題: 用 RSC (React Server Component) 搭配原生 fetch 來撈文章資料,程式碼看起來完全沒毛病,但實際卻會拋出 fetch error。
Sanity x Next.js 撈取 Post 資料踩坑紀錄

撈post資料出現錯誤

build error

錯誤範例

下面這段程式碼是直接用 fetch 呼叫 /api/posts API:

tsx
1// src/app/[lng]/(home)/_components/PostsSection.tsx
2import Grid from "@mui/material/Grid";
3import PostCards from "@/components/UI/PostCards";
4
5export default async function PostsSection() {
6  // SSR 取得文章資料
7  const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
8  const posts = await fetch(`${baseUrl}/api/posts`).then((res) => {
9    if (!res.ok) {
10      throw new Error("Failed to fetch posts");
11    }
12    return res.json();
13  });
14  return (
15    <Grid container spacing={2} columns={12}>
16      <PostCards posts={posts.data} />
17    </Grid>
18  );
19}
20

📌 看似正常,但實際跑起來會遇到 fetch error,原因就是 RSC 並不適合用這種方式去打 API


正確範例

解法是直接使用 Sanity 提供的 client.fetch,在 Server Component 中撈資料,不透過 /api/posts

tsx
1// src/app/[lng]/(home)/_components/PostsSection.tsx  ← Server Component(不要 "use client")
2import Grid from "@mui/material/Grid";
3import PostCards from "@/components/UI/PostCards";
4import {client} from "@/sanity/lib/client"
5import { PostDoc } from "@/schema/type/post";
6
7export default async function PostsSection() {
8  const posts = await client.fetch<PostDoc[]>(
9    `*[_type == "post"] | order(_createdAt desc) {
10      _id,
11      _createdAt,
12      title,
13      description,
14      photo,
15      "slug": slug.current,
16      categories[]->{
17        _id,
18        title,
19        "slug": slug.current
20      },
21      author->{
22        _id,
23        name,
24        "slug": slug.current,
25        email,
26        avatar
27      }
28    }`
29  );
30  return (
31    <Grid container spacing={2} columns={12}>
32      <PostCards posts={posts} />
33    </Grid>
34  );
35}
36

結論

  • 錯誤原因:RSC 中用原生 fetch 打 API,容易造成 fetch error
  • 解法:改用 Sanity 的 client.fetch,讓資料直接由 Server Component 撈取。

👉 總結:在 Next.js + Sanity 專案中,如果是 Server Component,不要走 API Route → fetch,直接用 client.fetch 就能避免踩坑。