如何在非React的普通JS/TS模块中调用useAuth暴露的refreshAccessToken方法
非React模块调用AuthProvider内方法的实现方案
核心思路是将AuthProvider内部的方法引用暴露到模块作用域,或者将拦截器注册逻辑移入AuthProvider的初始化流程中,两种可落地的实现方案如下:
方案1:全局模块引用挂载(最常用)
利用模块导出的可变对象存储AuthProvider的内部方法引用,组件初始化时对对象属性赋值,axios直接导入该对象即可拿到最新的方法。
步骤1:修改AuthProvider.ts
// AuthProvider.ts import { useEffect, useContext, createContext } from 'react' // 新增:导出模块级别的存储对象,默认值做兜底 export const authService = { getAccessToken: () => '', refreshAccessToken: async () => false, } const AuthContext = createContext({ login: () => {}, logout: () => {}, getAccessToken: () => '', refreshAccessToken: async () => false, }) export const AuthProvider: React.FC = ({ children }) => { // 原有内部逻辑实现 const login = () => {/* 原有逻辑 */} const logout = () => {/* 原有逻辑 */} const getAccessToken = () => {/* 原有读取localStorage逻辑 */} const refreshAccessToken = async () => {/* 原有刷新令牌、更新组件状态逻辑 */} // 新增:组件挂载时将内部方法赋值到全局存储对象 useEffect(() => { authService.getAccessToken = getAccessToken authService.refreshAccessToken = refreshAccessToken }, [getAccessToken, refreshAccessToken]) return ( <AuthContext.Provider value={{ login, logout, getAccessToken, refreshAccessToken }}> {children} </AuthContext.Provider> ) } export const useAuth = () => useContext(AuthContext)
步骤2:修改axios.ts
直接导入authService对象使用即可:
// axios.ts import axios from 'axios' import createAuthRefreshInterceptor from "axios-auth-refresh"; import { authService } from './AuthProvider' const apiEndipoint = '你的接口地址' const axiosAuthRefreshOptions = {/* 你的配置项 */} export const axiosApiInstance = axios.create({ baseURL: apiEndipoint, }); axiosApiInstance.interceptors.request.use((request) => { const token = authService.getAccessToken() if (token) { request.headers.Authorization = `Bearer ${token}` } return request; }); createAuthRefreshInterceptor( axiosApiInstance, authService.refreshAccessToken, axiosAuthRefreshOptions );
注意事项
- 必须保证
AuthProvider挂载在应用根组件外层,且在任意axios请求发起前完成初始化,常规业务场景都满足该条件 - 用对象存储而不是单独变量的原因是对象为引用类型,内部方法更新时所有导入的位置都会自动拿到最新值,不会出现闭包旧值问题
方案2:拦截器注册逻辑外置(无全局可变状态)
如果不想使用全局可变对象,可以把拦截器的注册逻辑封装为可传入auth方法的函数,在AuthProvider内部完成注册。
步骤1:修改axios.ts
// axios.ts import axios from 'axios' import createAuthRefreshInterceptor from "axios-auth-refresh"; const apiEndipoint = '你的接口地址' const axiosAuthRefreshOptions = {/* 你的配置项 */} export const axiosApiInstance = axios.create({ baseURL: apiEndipoint }); // 导出拦截器注册方法,接收auth方法作为入参 export const registerAxiosInterceptors = ( getAccessToken: () => string, refreshAccessToken: () => Promise<boolean> ) => { axiosApiInstance.interceptors.request.use((request) => { const token = getAccessToken() if (token) { request.headers.Authorization = `Bearer ${token}` } return request; }); createAuthRefreshInterceptor( axiosApiInstance, refreshAccessToken, axiosAuthRefreshOptions ); }
步骤2:修改AuthProvider.ts
在组件内部调用拦截器注册方法:
// AuthProvider.ts import { useEffect } from 'react' import { registerAxiosInterceptors } from './axios' export const AuthProvider: React.FC = ({ children }) => { const getAccessToken = () => {/* 原有逻辑 */} const refreshAccessToken = async () => {/* 原有逻辑 */} // 组件挂载时注册拦截器,依赖放空保证只注册一次 useEffect(() => { registerAxiosInterceptors(getAccessToken, refreshAccessToken) }, []) // 原有Provider逻辑 }
注意事项
- 可额外加去重逻辑避免拦截器重复注册,比如在axios.ts中加变量标记是否已经注册过
- 该方案无全局可变状态,可维护性更高
两种方案都能保证调用的是AuthProvider内部的原始refreshAccessToken方法,调用时可以正常触发组件内部状态更新,同步登录态到所有使用useAuth的组件中。
内容的提问来源于stack exchange,提问作者cool
相关产品推荐
相关产品推荐

