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

如何在非React组件中调用useAuth等React Hook获取用户token?

错误原因

你遇到的报错是React Hook的调用规则限制:所有React Hook(包括useAuth)只能在React函数组件的顶层或者自定义React Hook的顶层调用,你现在在普通JS对象的普通方法里调用Hook,不符合规则,所以直接报错。


可行解决方案(按推荐优先级排序)

方案1:配置Axios全局请求拦截器(最推荐,复用性最高,无需修改现有调用逻辑)

这个方案所有请求会自动注入token,还能统一处理响应、报错、token过期等通用逻辑,后续新增接口也不用重复写token相关代码。

  1. 抽离公共Axios实例配置文件,比如src/utils/request.js:
import Axios from "axios";
import { createUserManager } from "react-oidc-context";

// 这里的配置要和你根组件里AuthProvider的配置完全一致,建议抽成单独的公共配置文件避免重复
const userManager = createUserManager({
  authority: "<你的oidc认证地址>",
  client_id: "<你的客户端id>",
  redirect_uri: window.location.origin + "/callback",
  // 其他你原本的oidc配置...
});

// 创建自定义Axios实例
const request = Axios.create({
  baseURL: "<你的接口基础地址>",
  timeout: 10000,
});

// 请求拦截器:每次请求前自动注入token
request.interceptors.request.use(
  async (config) => {
    // 从userManager直接拿当前登录用户信息,无需调用Hook
    const user = await userManager.getUser();
    if (user?.access_token) {
      config.headers.Authorization = `Bearer ${user.access_token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器:统一处理返回值和报错,按需扩展
request.interceptors.response.use(
  (response) => response.data,
  (error) => {
    console.log("接口请求报错:", error);
    return Promise.reject(error);
  }
);

export default request;
  1. 改造你的ProductService,直接用封装好的request实例即可:
// ProductService.js
import request from "@/utils/request";

const ProductService = {
  getProductList: () => {
    return request.get("<myurl>");
  },
  getProduct: (productId: string) => {
    return request.get(`<myurl>/${productId}`);
  },
  addClient: (data: any) => {
    return request.post("<myurl>", data);
  }
}

export default ProductService;

方案2:在组件内拿token后传给服务方法(改动最小,适合小项目临时调整)

如果你不想修改现有Axios配置,可以直接在调用服务的组件内拿token,作为参数传给服务方法:

  1. 改造ProductService的方法,新增token参数:
// ProductService.js
import Axios from "axios";

const ProductService = {
  getProductList: (token: string) => {
    return Axios({
      method: "get",
      url: "<myurl>",
      headers: {
        "Authorization": token
      }
    }).then(res => res.data).catch(console.log);
  },
  getProduct: (productId: string, token: string) => {
    return Axios({
      method: "get",
      url: `<myurl>/${productId}`,
      headers: {
        "Authorization": token
      }
    }).then(res => res.data).catch(console.log);
  },
  addClient: (data: any, token: string) => {
    return Axios({
      method: "post",
      url: "<myurl>",
      data: data,
      headers: {
        "Authorization": token
      }
    }).then(res => res.data).catch(console.log);
  }
}
export default ProductService;
  1. 在业务组件内顶层调用useAuth拿token,调用服务时传入即可:
// 你的业务组件
import { useAuth } from "react-oidc-context";

const YourComponent = () => {
  // 组件顶层调用Hook,符合调用规则
  const auth = useAuth();
  const token = auth.user?.access_token;

  return (
    <Button 
      type="submit"
      onClick={() => {
        // 把token作为参数传入服务方法
        ProductService.addClient(data, token)
          .then(() => {
            toggleModal();
          });
      }}
    >
      Add
    </Button>
  )
}

缺点:每个调用服务的地方都需要手动传token,重复代码多


方案3:把ProductService封装成自定义Hook

如果你的服务逻辑和React组件绑定较深,可以把整个服务封装为自定义Hook,内部就能正常调用useAuth:

// useProductService.js
import Axios from "axios";
import { useAuth } from "react-oidc-context";

// 以use开头,符合自定义Hook的命名规则
const useProductService = () => {
  const auth = useAuth();
  const token = auth.user?.access_token;

  const getProductList = () => {
    return Axios({
      method: "get",
      url: "<myurl>",
      headers: {
        "Authorization": token
      }
    }).then(res => res.data).catch(console.log);
  };

  const getProduct = (productId: string) => {
    return Axios({
      method: "get",
      url: `<myurl>/${productId}`,
      headers: {
        "Authorization": token
      }
    }).then(res => res.data).catch(console.log);
  };

  const addClient = (data: any) => {
    return Axios({
      method: "post",
      url: "<myurl>",
      data: data,
      headers: {
        "Authorization": token
      }
    }).then(res => res.data).catch(console.log);
  };

  return {
    getProductList,
    getProduct,
    addClient
  }
}

export default useProductService;

在业务组件内使用时,先调用自定义Hook拿到服务方法即可:

const YourComponent = () => {
  // 组件顶层调用自定义Hook
  const { addClient } = useProductService();

  return (
    <Button 
      type="submit"
      onClick={() => {
        addClient(data)
          .then(() => {
            toggleModal();
          });
      }}
    >
      Add
    </Button>
  )
}

缺点:每个用到服务的组件都要先调用一次Hook,无法在非组件环境下调用服务


内容的提问来源于stack exchange,提问作者tickwave

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 13:09:00