如何在非React组件中调用useAuth等React Hook获取用户token?
错误原因
你遇到的报错是React Hook的调用规则限制:所有React Hook(包括useAuth)只能在React函数组件的顶层或者自定义React Hook的顶层调用,你现在在普通JS对象的普通方法里调用Hook,不符合规则,所以直接报错。
可行解决方案(按推荐优先级排序)
方案1:配置Axios全局请求拦截器(最推荐,复用性最高,无需修改现有调用逻辑)
这个方案所有请求会自动注入token,还能统一处理响应、报错、token过期等通用逻辑,后续新增接口也不用重复写token相关代码。
- 抽离公共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;
- 改造你的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,作为参数传给服务方法:
- 改造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;
- 在业务组件内顶层调用
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
相关产品推荐
相关产品推荐

