将组件设为Async时Next.js抛出错误,求生产可用解决方案
问题分析
你遇到的错误核心原因是:在Next.js客户端组件中,同时使用了React Hooks(useSession)和顶级await(await fetchVoiceCalls(token))。React Hooks必须在组件渲染的同步阶段调用,而异步组件的顶级await会打乱Hooks的执行顺序,触发React的Hooks规则错误。
解决办法
既然你不想用实验性的use钩子,我们可以用标准的useEffect结合状态管理来处理异步数据请求,同时避免不必要的重复请求:
步骤1:标记为客户端组件(App Router 必需)
如果组件在App Router目录下,先添加'use client'指令——因为useSession是客户端Hook,只能在客户端组件中使用。
步骤2:用useEffect+状态管理替代顶级await
通过useState管理数据、加载状态和错误状态,用useEffect在session变化时触发数据请求,确保只有token改变时才重新发起请求,避免无效调用。
修改后的代码:
'use client'; // App Router 下必须添加 import { useSession } from "next-auth/react"; import { useState, useEffect } from "react"; export default function StatsPage() { const { data: session } = useSession(); const [voiceData, setVoiceData] = useState<string | null>(null); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState<string | null>(null); // 提取token,简化逻辑 const token = session?.user?.data?.auth_tokens["bearer-token"] || ""; useEffect(() => { // 无token时直接返回,避免无效请求 if (!token) return; const fetchData = async () => { setIsLoading(true); setError(null); try { const data = await fetchVoiceCalls(token); setVoiceData(data); } catch (err) { setError("获取通话数据失败"); console.error(err); } finally { setIsLoading(false); } }; fetchData(); }, [token]); // 依赖token,仅当token变化时重新请求 // 渲染不同状态的UI if (isLoading) return <div>加载中...</div>; if (error) return <div>错误:{error}</div>; if (!voiceData && !token) return <div>请先登录</div>; return ( <div> <h1>通话统计</h1> <p>{voiceData}</p> </div> ); } async function fetchVoiceCalls(token: string) { const requestOptions = { method: "GET", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, }; const res = await fetch(`end-point-here`, requestOptions); // 检查响应状态,主动抛出错误 if (!res.ok) { throw new Error(`请求失败:${res.status}`); } // 可根据实际接口返回解析数据,比如 return res.json(); return "something"; }
关键改动说明
- 移除组件的
async声明,避免顶级await破坏Hooks执行规则 - 用
useEffect监听token变化,仅在token有效且更新时发起请求,杜绝不必要的重复调用 - 添加加载、错误状态管理,优化用户体验
- 在
fetchVoiceCalls中增加响应状态校验,捕获请求失败场景,避免未处理的Promise错误
内容的提问来源于stack exchange,提问作者sylvesterasa
相关产品推荐
相关产品推荐

