如何等待NextAuth会话加载?解决手动输入URL的Token读取报错问题
解决NextAuth页面刷新时session未加载导致的accessToken读取错误
问题场景
使用NextAuth实现用户认证,将accessToken存储在session中。在[trackId].js页面,通过useState的refresh状态变化触发useEffect获取最新曲目数据,正常操作无异常,但手动输入URL刷新页面时,出现如下错误:
TypeError: Cannot read properties of undefined (reading 'accessToken')
原因是页面刷新时session处于loading状态,session.data仍为undefined,accessToken尚未加载完成。
解决方案
方案1:组件层面处理session加载状态
在组件中通过useSession获取session的同时,判断loading状态,在session未加载完成前不渲染业务内容,避免触发错误请求:
import { useSession } from "next-auth/react"; import { useState, useEffect } from "react"; export default function TrackPage({ trackId }) { const { data: session, loading } = useSession(); const [refresh, setRefresh] = useState(false); const [getedTrack, setGetedTrack] = useState(null); // 加载中时显示占位内容 if (loading) return <div>加载中...</div>; // 未登录时跳转或提示 if (!session) return <div>请先登录</div>; useEffect(() => { async function refreshPage() { await axiosPrivateWithToken(session.data.accessToken) .get(`/track/get/${trackId}`) .then((res) => setGetedTrack(res.data)) .catch((error) => console.log("刷新曲目失败: ", error)); } refreshPage(); }, [refresh, session.data.accessToken]); // 页面核心渲染内容 return <div>{/* 曲目展示内容 */}</div>; }
方案2:在useEffect内校验session有效性
修改useEffect的依赖数组,加入session,并在请求前先校验accessToken是否存在,避免读取undefined属性:
useEffect(() => { async function refreshPage() { // 先校验session及accessToken的有效性 if (!session?.data?.accessToken) { console.log("Session未就绪或用户未登录"); return; } await axiosPrivateWithToken(session.data.accessToken) .get(`/track/get/${trackId}`) .then((res) => setGetedTrack(res.data)) .catch((error) => console.log("刷新曲目失败: ", error)); } refreshPage(); }, [refresh, session]); // 将session加入依赖,确保状态更新时重新执行
方案3:服务端预获取session(SSR方式)
通过getServerSideProps在服务端获取session,将accessToken作为props传递给页面,彻底避免客户端加载延迟问题:
import { getSession } from "next-auth/react"; import { useState, useEffect } from "react"; export async function getServerSideProps(context) { const session = await getSession(context); // 未登录时直接跳转登录页 if (!session?.data?.accessToken) { return { redirect: { destination: "/login", permanent: false, }, }; } return { props: { accessToken: session.data.accessToken }, }; } export default function TrackPage({ trackId, accessToken }) { const [refresh, setRefresh] = useState(false); const [getedTrack, setGetedTrack] = useState(null); useEffect(() => { async function refreshPage() { await axiosPrivateWithToken(accessToken) .get(`/track/get/${trackId}`) .then((res) => setGetedTrack(res.data)) .catch((error) => console.log("刷新曲目失败: ", error)); } refreshPage(); }, [refresh, accessToken]); return <div>{/* 曲目展示内容 */}</div>; }
内容的提问来源于stack exchange,提问作者Ahmed Sbai
相关产品推荐
相关产品推荐

