Next.js 13导航栏报错:客户端组件不支持async/await,求解决
解决Next.js 13客户端组件中引入async组件的错误
错误原因
标记了"use client"的Navbar组件(客户端组件)无法直接渲染async函数组件。Next.js 13中,async函数组件默认属于服务器组件,客户端组件不支持嵌套渲染异步服务器组件——因为客户端环境无法处理组件级别的async/await逻辑。
方案1:将async组件转为服务器组件,通过动态导入使用
该方案保留服务器端数据获取的优势(缓存、预渲染),适合需要服务器端预加载数据的场景。
步骤:
- 确保
DataManufactureNav组件没有添加"use client"标记,保持它作为异步服务器组件(你的现有代码已经满足这一点)。 - 在
navbar.tsx顶部添加动态导入代码:import dynamic from 'next/dynamic'; // 动态导入服务器组件,ssr设为true确保在服务器端完成渲染 const DataManufactureNav = dynamic(() => import('./path-to/DataManufactureNav'), { ssr: true }); Navbar中使用<DataManufactureNav />的代码无需修改,直接保留即可。
方案2:将async组件转为客户端组件,用客户端数据获取逻辑
如果不需要服务器端预渲染数据,可以把DataManufactureNav改成客户端组件,在客户端用useEffect获取数据:
修改DataManufactureNav代码:
"use client"; import { useEffect, useState } from 'react'; import Link from 'next/link'; function DataManufactureNav() { const [data, setData] = useState<categoriesDTO[] | []>([]); const [isError, setIsError] = useState(false); const [isLoading, setIsLoading] = useState(true); useEffect(() => { const fetchCategories = async () => { try { const res = await fetch("http://localhost:8081/product/categories", { next: { revalidate: 3600 }, }); if (res.ok) { const categories = await res.json(); setData(categories); } else { setIsError(true); } } catch (err) { setIsError(true); } finally { setIsLoading(false); } }; fetchCategories(); }, []); if (isLoading) return <div>加载中...</div>; if (isError) return <div>加载出错</div>; return ( <> {data.length > 0 ? ( data.map(item => ( <li key={item.CATEGORY_ID}> <Link className="nav-link" href={`/categories/${item.CATEGORY_ID}`}> {item.CATEGORY_NAME} </Link> </li> )) ) : ( <div>暂无数据</div> )} </> ); } export default DataManufactureNav;
修改后,DataManufactureNav成为客户端组件,可直接在Navbar中导入使用,无需额外配置。
方案3:拆分组件为服务器端数据获取+客户端渲染
该方案分离数据获取与渲染逻辑,服务器组件负责获取数据,客户端组件负责渲染:
创建服务器组件
ManufactureNavServer.tsx,负责获取数据:import dynamic from 'next/dynamic'; // 动态导入客户端渲染组件 const ManufactureNavClient = dynamic(() => import('./ManufactureNavClient'), { ssr: false }); async function ManufactureNavServer() { let data: categoriesDTO[] | [] = []; const res = await fetch("http://localhost:8081/product/categories", { next: { revalidate: 3600 }, }); if (res.ok) { data = await res.json(); } // 将获取到的数据传给客户端组件 return <ManufactureNavClient data={data} />; } export default ManufactureNavServer;创建客户端组件
ManufactureNavClient.tsx,负责渲染:"use client"; import Link from 'next/link'; export default function ManufactureNavClient({ data }: { data: categoriesDTO[] | [] }) { return ( <> {data.length > 0 ? ( data.map(item => ( <li key={item.CATEGORY_ID}> <Link className="nav-link" href={`/categories/${item.CATEGORY_ID}`}> {item.CATEGORY_NAME} </Link> </li> )) ) : ( <div>暂无数据</div> )} </> ); }在
navbar.tsx中导入并使用服务器组件:import dynamic from 'next/dynamic'; const ManufactureNavServer = dynamic(() => import('./ManufactureNavServer'), { ssr: true }); // 在Navbar的JSX中替换原<DataManufactureNav />为: <ManufactureNavServer />
内容的提问来源于stack exchange,提问作者Frank
相关产品推荐
相关产品推荐

