Next.js 13刷新报async/await客户端组件错误,路由跳转正常求助
可能的原因
客户端组件嵌套了含异步逻辑的客户端组件
错误提示指向客户端组件内使用了async/await,但你的代码里没有直接写相关逻辑,大概率是你引用的Container或Navbar组件(都是客户端组件)内部存在顶层async/await,或是在渲染阶段执行了异步函数。刷新页面时触发SSR(服务器端渲染),Next.js会检测到客户端组件中的异步逻辑并报错;而通过<Link />跳转是客户端路由(CSR),不会触发服务器端的检测,因此无报错。Zustand Store的SSR Hydration不匹配
虽然你的useProfile是同步创建的,但在SSR环境下,服务器端生成的初始状态(profile: null)和客户端hydration时的状态可能存在差异,导致Next.js抛出错误,且错误提示被误判为async/await相关问题。这种情况在状态管理库的SSR适配不到位时很常见。Next.js版本bug
Next.js 13的App Router早期版本存在一些错误提示不准确的问题,可能把 hydration 不匹配或其他渲染错误误报为async/await不支持。
解决方案
1. 排查依赖组件的异步逻辑
- 检查
@/components/Container和@/components/Navbar的代码:- 如果它们是客户端组件(带有
"use client"指令),确保没有顶层async/await,也没有在组件渲染函数中调用异步函数。 - 如果这些组件需要异步获取数据,将其改为服务器组件(移除
"use client",直接在组件内用async/await获取数据),客户端组件可以正常嵌套服务器组件。
- 如果它们是客户端组件(带有
2. 修复Zustand的SSR Hydration问题
给useProfile添加SSR适配,确保服务器端和客户端状态一致:
// ./hooks/useProfile.tsx import { create } from "zustand"; import { persist, createJSONStorage } from "zustand/middleware"; import { SavedProfile } from "@/lib/server-functions/utils/types"; interface ProfileState { profile: SavedProfile | null; setProfile: (profile: SavedProfile) => void; } export const useProfile = create<ProfileState>()( persist( (set) => ({ profile: null, setProfile: (profile: SavedProfile) => set({ profile }), }), { name: "profile-storage", storage: createJSONStorage(() => sessionStorage), // 禁用SSR时的persist,避免状态不匹配 skipHydration: true, } ) );
如果不需要本地持久化,也可以在服务器组件中预先设置初始状态,确保客户端hydration时状态一致:
// 新建一个服务器组件,比如./components/HydrateProfile.tsx import { useProfile } from "@/hooks/useProfile"; import { getProfile } from "@/lib/server-functions"; // 假设这是获取用户信息的服务器函数 export async function HydrateProfile() { const profile = await getProfile(); useProfile.setState({ profile }); return null; } // 在根layout.tsx(服务器组件)中引入 export default async function RootLayout({ children }) { return ( <html lang="en"> <body> <HydrateProfile /> {children} </body> </html> ); }
3. 升级Next.js版本
将Next.js升级到最新稳定版,很多早期版本的错误提示和渲染逻辑bug都已被修复。
4. 验证路由结构差异
对比正常页面和报错页面的路由层级与父组件,确认是否存在父layout为客户端组件且包含异步逻辑的情况,若有则调整为服务器组件。
内容的提问来源于stack exchange,提问作者Adam El Taha

