Next.js App Router如何实现服务端渲染转客户端动态渲染?
在Next.js App Router中实现「服务端渲染初始数据 + 客户端动态更新」模式
要在App Router中实现你原来Pages Router的模式,核心是利用服务端组件获取初始数据,再将数据传递给客户端组件处理交互逻辑,以下是具体实现方案:
核心思路
- 服务端组件:直接在页面组件中通过
async/await获取初始数据(替代getServerSideProps),确保首次渲染是服务端渲染的完整内容。 - 客户端组件:标记
'use client'指令,接收服务端传递的初始数据,用useState管理本地状态,处理点击等交互逻辑。
完整代码示例
// app/about/page.tsx // 服务端组件:负责获取初始数据(替代getServerSideProps) async function AboutPage() { // 禁用缓存,确保每次请求都获取最新数据(和getServerSideProps行为一致) const res = await fetch(`/api/myData`, { cache: 'no-store' }); const initialData = await res.json(); // 将初始数据传递给客户端组件 return <AboutClient initialData={initialData} />; } export default AboutPage; // 客户端组件:负责交互和状态管理 'use client'; import { useState } from 'react'; type AboutClientProps = { initialData: any[]; }; function AboutClient({ initialData }: AboutClientProps) { const [data, setData] = useState(initialData); const addItem = async () => { // 修正原代码的async缺失问题,同时优化fetch请求处理 const res = await fetch('/api/addData', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ item: 'foo' }) }); const responseData = await res.json(); // 使用函数式更新确保状态是最新的 setData(prevData => [...prevData, responseData.item]); }; return ( <div> {data.map((item, index) => ( <div key={index}>{item}</div> ))} <button onClick={addItem}>Add Item</button> </div> ); }
关键细节说明
- 服务端数据获取配置:
fetch默认会缓存请求结果,如果需要和getServerSideProps一样的动态获取行为(每次请求都拉取最新数据),必须添加{ cache: 'no-store' },或者在服务端组件顶部添加export const dynamic = 'force-dynamic';。 - 客户端组件标记:任何需要使用React hooks(如
useState)、事件处理的组件,必须添加'use client'指令,否则Next.js会视为服务端组件,无法在客户端执行交互逻辑。 - 状态更新优化:使用
setData(prevData => ...)的函数式更新方式,避免因闭包导致的状态更新不准确问题。 - 原代码问题修正:你原来的
addItem函数缺少async关键字(直接使用await会报错),同时res.body的解析方式可以用更简洁的res.json()替代。
内容的提问来源于stack exchange,提问作者Ryan O'Neill
相关产品推荐
相关产品推荐

