React Server Component在Suspense中渲染后客户端崩溃求助
React Server Component迁移后客户端崩溃问题排查与解决
问题情况
将React组件迁移为React Server Component(RSC),标记为async并使用<Suspense>包裹后,服务端能正常接收请求、渲染组件并返回响应,但客户端出现崩溃,无法正常显示组件,同时抛出状态更新相关警告。
代码示例
page.tsx
<Suspense fallback={<div>Loading...</div>}> <TestServerComponent> {JSON.stringify(content, undefined, 4)} </TestServerComponent> </Suspense>
TestServerComponent.tsx
'use server' export async function TestServerComponent(props?: PropsWithChildren) { console.log('TestServerComponent render:', props) return ( <pre>{props?.children}</pre> ) }
服务端与响应信息
- 服务端日志:
TestServerComponent render: { children: '{\n "test": true\n}' }
- HTTP响应内容:
0:["$@1",["development",null]] 1:["$","pre",null,{"children":"{\n \"test\": true\n}"}]
客户端错误
Warning: Cannot update a component (
Router) while rendering a different component (proxy). To locate the bad setState() call insideproxy, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
at proxy
at Suspense
at div
at Page (webpack-internal:///(app-pages-browser)/./app/page.tsx:15:82)
## 问题原因 核心问题在于**服务器组件(RSC)接收了客户端生成的`children`**: - RSC的渲染逻辑完全在服务端执行,你在客户端通过`JSON.stringify(content...)`生成children并传递给RSC,会导致服务端渲染的静态内容与客户端hydration时的动态计算结果出现一致性冲突。 - React在hydration过程中检测到内容不匹配,触发内部状态调整,进而引发Router组件的状态更新警告(Router会因组件渲染异常尝试修正状态)。 ## 解决方案 ### 方案1:将数据处理逻辑移至服务器组件内部 如果`content`可以在服务端获取或处理,直接在RSC内部完成序列化操作,避免客户端传递动态children: ```tsx // TestServerComponent.tsx 'use server' export async function TestServerComponent() { // 服务端获取content(示例为本地数据,实际可从数据库/API获取) const content = { test: true }; const contentStr = JSON.stringify(content, undefined, 4); console.log('TestServerComponent render:', contentStr) return ( <pre>{contentStr}</pre> ) }
// page.tsx <Suspense fallback={<div>Loading...</div>}> <TestServerComponent /> </Suspense>
方案2:通过props传递序列化后的内容(而非children)
如果content必须在客户端生成,将序列化后的字符串通过props传递给RSC(确保props是可序列化的JSON类型):
// page.tsx <Suspense fallback={<div>Loading...</div>}> <TestServerComponent contentStr={JSON.stringify(content, undefined, 4)} /> </Suspense>
// TestServerComponent.tsx 'use server' export async function TestServerComponent({ contentStr }: { contentStr: string }) { console.log('TestServerComponent render:', contentStr) return ( <pre>{contentStr}</pre> ) }
注意:如果
content是客户端状态(如useState的返回值),确保传递给RSC的contentStr是可序列化的基础类型,避免传递复杂对象或React节点。
内容的提问来源于stack exchange,提问作者teos
相关产品推荐
相关产品推荐

