NextJS中如何结合session的access_token使用useSWR请求后端数据?
问题与解决方案
问题背景
用NextJS + Next-auth(credentials provider)实现前端认证,后端基于Django。用户通过Django认证后,用户信息和access_token会存在Next-auth的session中。现在想用useSWR从后端拉取数据,需要在请求头里带上session中的access_token,但直接把useSWR放在认证成功的条件分支里,触发了错误:Error: Rendered more hooks than during the previous render.
核心需求:确保所有后端请求的Authorization头都包含自定义后端返回的access_token。
错误原因
React Hooks规则明确要求:不能在条件判断、循环、嵌套函数中调用Hooks。原代码里把useSWR放在if (status == "authenticated")分支里,导致组件渲染时Hooks的调用数量不稳定,触发了上述错误。
解决方案
方案思路
- 把
useSWR移到组件顶层,严格遵守Hooks调用规则。 - 通过动态控制请求URL(未认证时设为
null),让useSWR只在认证成功后发起请求。 - 让fetcher动态获取当前session的
access_token,保证每次请求都携带最新的token。
修正后的代码
import { useSession } from "next-auth/react"; import useSWR from 'swr'; import axios from 'axios' export default function Profile() { const { data: session, status } = useSession(); // 顶层调用useSWR,未认证时url设为null,不会发起请求 const url = status === "authenticated" ? "http://mybackend.com/user/" : null; // 动态生成fetcher,每次请求都从当前session拿token const fetcher = (url) => { const config = { headers: { Authorization: `Bearer ${session.access_token}` } }; return axios.get(url, config).then(res => res.data); }; const { data, error } = useSWR(url, fetcher); // 处理加载状态 if (status === "loading") { return <span>Loading...</span>; } // 处理未认证状态 if (status === "unauthenticated") { return <span>请先登录</span>; } // 认证成功后渲染数据 if (error) return <span>获取数据失败</span>; if (!data) return <span>加载数据中...</span>; return <span>{data.email}</span>; }
额外优化建议
可以封装一个全局的axios实例,自动从session中获取token并添加请求头,避免每个组件重复写请求头逻辑:
// utils/axios.js import axios from 'axios'; import { useSession } from "next-auth/react"; export function useAuthAxios() { const { data: session } = useSession(); const authAxios = axios.create({ baseURL: "http://mybackend.com/" }); // 请求拦截器,自动添加Authorization头 authAxios.interceptors.request.use((config) => { if (session?.access_token) { config.headers.Authorization = `Bearer ${session.access_token}`; } return config; }); return authAxios; }
然后在组件中使用:
import { useSession } from "next-auth/react"; import useSWR from 'swr'; import { useAuthAxios } from '../utils/axios'; export default function Profile() { const { status } = useSession(); const authAxios = useAuthAxios(); const url = status === "authenticated" ? "/user/" : null; const fetcher = (url) => authAxios.get(url).then(res => res.data); const { data, error } = useSWR(url, fetcher); // 状态处理逻辑同上... }
内容的提问来源于stack exchange,提问作者JHNT
相关产品推荐
相关产品推荐

