Next.js 13/14客户端组件用use钩子获取服务端数据失败问题
问题分析与解决
为什么use钩子会报错?
你误解了React use钩子的适用场景:
use钩子的设计目的是解析已在服务端生成的Promise,比如从服务端组件传递给客户端组件的异步数据Promise,或是配合Suspense处理组件懒加载这类场景。- 当你在客户端组件里直接调用
getBottomMenuData()并传入use钩子时,这个调用会在客户端执行——尽管getBottomMenuData标记了'use server',但在客户端组件的渲染流程中直接调用它,会触发React的校验机制:客户端组件的渲染阶段不允许执行异步逻辑,因此抛出了async/await is not yet supported in Client Components的错误。
而useEffect + useState能正常工作的原因是:
useEffect的回调是在组件挂载后的客户端副作用阶段执行的,不属于组件渲染流程,因此可以安全调用异步函数并更新状态。
正确的解决方案
如果想在客户端组件中使用use钩子配合服务端数据,需要通过服务端组件作为中间层传递Promise:
- 创建服务端组件,在其中调用服务端函数并传递Promise给客户端组件:
// 无'use client'标记,属于服务端组件 import { BottomMenu } from "./BottomMenuClient"; import { getBottomMenuData } from "./BottomMenuData"; export async function BottomMenuWrapper() { const dataPromise = getBottomMenuData(); return <BottomMenu dataPromise={dataPromise} />; }
- 修改客户端组件,接收Promise并使用
use钩子解析:
"use client" import styles from "./BottomMenu.module.css" import { ActiveType } from "./BottomMenuData"; import { use } from "react"; type BottomMenuProps = { dataPromise: Promise<ActiveType>; }; export function BottomMenu({ dataPromise }: BottomMenuProps) { const active = use(dataPromise); return <div>当前激活项:{active}</div>; }
这样getBottomMenuData的调用在服务端完成,传递给客户端的只是一个Promise,use钩子在客户端组件中解析这个Promise就不会触发报错。
总结
- 客户端组件的渲染阶段不能直接执行异步逻辑,
use钩子不能用来直接调用服务端action,只能解析已在服务端生成的Promise。 useEffect + useState是客户端组件中直接调用服务端action的常规方式,use钩子则需要配合服务端组件传递Promise的模式使用。
内容的提问来源于stack exchange,提问作者marius
相关产品推荐
相关产品推荐

