
在 Next.js App Router 中,可通过在服务端组件(如 page.js)中预获取数据并直接作为 props 传入 'use client' 组件,实现数据缓存与服务端渲染优势,避免客户端重复请求。
在 next.js app router 中,可通过在服务端组件(如 `page.js`)中预获取数据并直接作为 props 传入 `'use client'` 组件,实现数据缓存与服务端渲染优势,避免客户端重复请求。
Next.js 的 App Router 鼓励“数据获取前置”(data fetching at the edge),即尽可能在服务端完成数据获取,并通过 props 将结构化数据传递给客户端组件。这种模式不仅提升首屏性能、支持静态生成(SSG)或服务端渲染(SSR),还能利用 Next.js 内置的自动缓存与重新验证机制(如 fetch(..., { next: { revalidate: 3600 } })),彻底规避客户端反复调用 API 的开销。
✅ 正确做法:在 page.js 中异步获取并透传数据
page.js 默认是服务端组件,且支持 async/await —— 这是关键前提。你只需在此处调用 fetch 或封装好的数据函数,然后将结果作为 props 传入客户端组件:
// app/page.tsx
import Home from './clientComponent';
import { API } from '@/utils/api';
export default async function Page() {
const data = await getData();
return <Home data={data} />;
}
async function getData() {
const res = await fetch(API.pages.retrieve(1), {
// ✅ 启用 Next.js 自动缓存(默认 30 秒)
// next: { revalidate: 3600 }, // 可选:每小时重新验证
});
if (!res.ok) {
throw new Error(`Failed to fetch page data: ${res.status}`);
}
return res.json();
}⚠️ 注意:必须声明为 async function Page(),否则 await 将报错;同时确保 fetch 调用在服务端上下文(即非 'use client' 文件内)执行。
✅ 客户端组件接收并消费数据
客户端组件需显式标注 'use client',仅负责交互逻辑与动态渲染,不参与数据获取:
// app/clientComponent.tsx
'use client';
import { Fragment } from 'react';
import Image from 'next/image';
import Typography from '@mui/material/Typography'; // 示例 UI 库
import styles from './page.module.css';
export default function Home({ data }: { data: any }) {
// ✅ 安全访问嵌套数据(建议添加类型守卫或使用 optional chaining)
const set1 = data?.textblockset?.find((item: any) => item.id === 1);
if (!set1 || !Array.isArray(set1.textblock)) {
return <main className={styles.main}>加载中或数据异常</main>;
}
return (
<main className={styles.main}>
{set1.textblock.map((item: any) => (
<Fragment key={item.id}>
{item.block_icon && (
<Image
src={item.block_icon}
alt="icon"
width={50}
height={50}
loading="lazy"
className={styles.icon}
/>
)}
<Typography paragraph fontWeight="bold">
{item.block_title}
</Typography>
<Typography>{item.block_content}</Typography>
</Fragment>
))}
</main>
);
}❌ 常见错误与避坑指南
错误:在客户端组件中尝试 await 或 fetch
→ 客户端组件无法直接使用服务端 fetch(除非显式发起 HTTP 请求),且违背“数据前置”原则,失去缓存能力。错误:用 <Client><Server /></Client> 嵌套方式试图“返回 props”
→ React 不允许 Server Component 返回 { props: {...} } 对象——这会被当作 JSX 子元素渲染,触发 Objects are not valid as a React child 错误。Server Component 必须返回合法 JSX 元素(如 <div>...</div>),而非配置对象。错误:未处理空值或结构变化导致运行时崩溃
→ 使用可选链(?.)、默认值(?? [])或 zod/tRPC 类型校验增强健壮性。-
进阶建议:
- 为 data 添加 TypeScript 接口(如 PageData),提升开发体验与安全性;
- 在 fetch 中启用 cache: 'force-cache'(默认)或 revalidate 精细控制缓存策略;
- 若 Home 组件实际无需状态或事件处理器,可考虑完全转为 Server Component,进一步减少客户端包体积。
通过以上方式,你既能享受服务端数据缓存带来的性能与 SEO 优势,又能保留客户端组件所需的交互能力,真正践行 Next.js “按需水合”(selective hydration)的设计哲学。









