Next.js中如何在getStaticProps中获取AuthContext存储的用户accessToken?
首先得明确一个核心问题:getStaticProps根本没法直接访问React的Context或者hooks,这是Next.js的设计逻辑决定的——getStaticProps是在**构建阶段(或者ISR的后台刷新阶段)**运行的,它完全脱离React组件树,既不在客户端浏览器环境,也不参与组件的渲染流程,所以你调用useAuth钩子才会触发那个错误。
那怎么解决你的需求呢?给你几个实用的方案,你可以根据自己的业务场景选择:
方案一:改用getServerSideProps获取用户token
如果你的页面需要针对每个登录用户展示个性化数据,且能接受服务器端渲染(SSR)的性能损耗,那把getStaticProps换成getServerSideProps是最直接的办法。
getServerSideProps会在每次用户请求页面时在服务器端运行,虽然它也不能直接用React hooks,但你可以从请求的Cookie(或者请求头)里拿到用户的accessToken——毕竟用户登录后,token一般会存在Cookie或者localStorage里,而Cookie会自动随请求发送到服务器。
举个具体的例子(假设你的token存在名为accessToken的Cookie里):
import cookie from 'cookie'; import axios from 'axios'; export async function getServerSideProps(context) { // 解析请求头里的Cookie const cookies = cookie.parse(context.req.headers.cookie || ''); const accessToken = cookies.accessToken; // 如果没有token,直接重定向到登录页 if (!accessToken) { return { redirect: { destination: '/login', permanent: false, }, }; } try { // 带着token请求API const result = await axios.get("http://127.0.0.1:5000/track/landing-tracks-for-admin", { headers: { Authorization: `Bearer ${accessToken}` } }); return { props: { tracks: result.data, }, }; } catch (error) { // 处理token过期或无效的情况,比如重定向登录 return { redirect: { destination: '/login', permanent: false, }, }; } }
方案二:在客户端组件内获取数据
如果你的页面可以接受“先展示静态骨架,再在客户端加载用户专属数据”的体验,那可以保留getStaticProps(用来生成静态页面的基础结构),然后在组件内部借助AuthContext拿到token,再请求API。
推荐用SWR或者React Query这类数据获取库,它们能帮你处理缓存、重新请求等逻辑,比原生useEffect更优雅:
import useAuth from "../../hooks/useAuth"; import useSWR from 'swr'; // 封装带token的请求函数 const fetcher = (url, token) => axios.get(url, { headers: { Authorization: `Bearer ${token}` } }).then(res => res.data); export default function AdminTracksPage() { const { auth } = useAuth(); // 只有当token存在时才发起请求 const { data: tracks, error } = useSWR( auth.accessToken ? ["http://127.0.0.1:5000/track/landing-tracks-for-admin", auth.accessToken] : null, fetcher ); if (error) return <div>加载曲目失败,请稍后重试</div>; if (!tracks) return <div>加载中...</div>; // 渲染你的曲目列表 return ( <div className="track-list"> {tracks.map(track => ( <div key={track.id}>{track.name}</div> ))} </div> ); } // 用getStaticProps生成静态页面的基础结构 export async function getStaticProps() { return { props: {}, // 不需要传递动态数据,因为数据在客户端获取 revalidate: 5, }; }
方案三:特殊场景:静态生成+个性化数据(不推荐)
如果你的业务必须用getStaticProps(比如需要完全静态化且CDN缓存),但又要展示用户个性化数据,这种场景其实非常矛盾——静态生成的页面是通用的,没法针对每个用户定制。
唯一的折中方式是把用户ID作为路由参数(比如/admin/tracks/[userId]),然后用getStaticPaths预生成所有可能的用户页面,但这显然不现实(用户数量多的话根本生成不过来),而且token的安全性也没法保证,所以这个方案只适合极少数特殊场景,一般不推荐。
总结一下:如果需要服务器端实时获取用户数据,选方案一;如果可以接受客户端加载数据,选方案二;方案三尽量不要用。
备注:内容来源于stack exchange,提问作者Ahmed Sbai

