React服务端组件报错:初始渲染无法调用Server Functions的原因探究
我有一个带'use client'指令的CampaignTable客户端组件,它通过columns对象渲染数据表格列。在columns定义中,我引入了CampaignActions服务端组件——这是一个带下拉菜单的组件,会调用API获取数据并在弹窗中使用。
但现在页面变得异常缓慢,还抛出错误:
Error: Server Functions cannot be called during initial render. This would create a fetch waterfall. Try to use a Server Component to pass data to Client Components instead.
我认为CampaignActions已经是服务端组件,但为什么会出问题?我知道可以通过在顶层页面先调用API,再把数据通过props从Page→CampaignTable→CampaignActions传递的方式解决,但我更想搞懂当前方法错误的原因——如果能在需要数据的组件里直接调用API,不用层层传参就好了。
代码示例
CampaignTable(客户端组件)
'use client' import React from "react"; const CampaignTable = (props: CampaignTableProps) => { const campaignColumns = useMemo(() => ( [ columnHelper.accessor("id", { header: () => "ID", cell: info => info.getValue() }), columnHelper.display({ id: "socials", header: () => "Actions", cell: ({row}) => { return ( <CampaignActions {...row.original}/> ) } }), ] ), []) return ( <DataTable data={props.campaigns || []} columns={campaignColumns} /> )}
CampaignActions(预期为服务端组件)
async function CampaignActions(props: Campaign){ const {data: clients} = await getAllClients().then((res) => res); return ( <DataTableActions edit={{ onEdit: async () => { await openUpdateCampaignModal({ ...props, clients: clients ?? [], }) } }} /> )}
服务端组件被强制降级:虽然
CampaignActions本身是服务端组件,但它被直接嵌套在带'use client'的CampaignTable组件中渲染,这会让CampaignActions被强制转为客户端组件上下文。客户端组件不允许在顶层使用async/await执行服务端API调用,这是错误触发的核心原因。触发fetch瀑布流与性能浪费:即便
CampaignActions能保持服务端身份,它在表格的cell渲染逻辑中被实例化,意味着表格每一行都会触发一次getAllClients()调用。初始渲染时大量并行/串行请求会直接拖慢页面,同时违反Next.js服务端渲染的设计原则——服务端组件的顶层数据获取应该在组件树高层执行,避免渲染过程中动态发起请求导致的瀑布流。错误提示的本质:Next.js禁止在初始渲染阶段(尤其是客户端组件上下文内)调用服务端函数,因为这会导致客户端渲染时发起服务端请求,既破坏服务端渲染的性能优化,又容易产生不可控的请求瀑布。
如果你想尽量减少props传递层级,可以考虑用React Context封装clients数据,但必须在服务端组件中初始化Context并传入预获取的数据,避免在客户端组件中发起API请求。
内容的提问来源于stack exchange,提问作者Re-Angelo

