You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在非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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 14:45:06