自定义Hook中带Token的Axios实例仅首次请求有效问题求助
问题分析与解决方案
问题根源
你的自定义Hook存在以下核心问题:
- 未缓存Axios实例:每次调用
useAxiosAuthenticated都会创建新的Axios实例,组件重新渲染时会生成新实例,若业务逻辑复用了旧实例,会出现拦截器未正确配置的情况,导致后续请求无法携带有效Token。 - 拦截器未清理:多次添加拦截器且未做清理,可能引发内存泄漏,甚至导致请求逻辑异常。
- 存入state的异步问题:将Axios实例存入state时,由于state更新是异步的,组件首次渲染时无法获取到已配置拦截器的实例,直接触发401错误。
修正后的Hook实现
import { useAuth0 } from "@auth0/auth0-react"; import axios, { AxiosInstance } from "axios"; import { useEffect, useMemo } from "react"; export default function useAxiosAuthenticated() { const { getAccessTokenSilently } = useAuth0(); // 用useMemo缓存Axios实例,仅当依赖变化时重新创建 const axiosInstance = useMemo(() => { const instance = axios.create({ baseURL: GeneralHelper.APIUrl, }); // 添加请求拦截器并记录ID,用于后续清理 const interceptorId = instance.interceptors.request.use( async (config) => { const token = await getAccessTokenSilently(); config.headers.Authorization = `Bearer ${token}`; return config; }, (error) => Promise.reject(error) ); return { instance, interceptorId }; }, [getAccessTokenSilently]); // 组件卸载时清理拦截器,避免内存泄漏 useEffect(() => { const { instance, interceptorId } = axiosInstance; return () => { instance.interceptors.request.eject(interceptorId); }; }, [axiosInstance]); return axiosInstance.instance; }
关键修正点说明
- 缓存实例:通过
useMemo缓存Axios实例,仅在getAccessTokenSilently变化时重新创建,确保实例的稳定性,避免组件渲染时重复生成实例。 - 拦截器生命周期管理:添加拦截器时记录ID,在组件卸载时调用
eject清理,避免内存泄漏和重复拦截逻辑。 - 直接返回就绪实例:无需将实例存入state,组件调用Hook时即可获取已配置好拦截器的实例,保证首次请求就能正常携带Token。
使用方式
在组件中直接调用Hook获取实例即可,无需额外配置:
const axiosAuth = useAxiosAuthenticated(); // 发起请求 axiosAuth.get("/api/data") .then(res => console.log(res.data)) .catch(err => console.error(err));
内容的提问来源于stack exchange,提问作者user17145524
相关产品推荐
相关产品推荐

