TypeScript/React中Axios调用报错:'() => AxiosCacheInstance'无get属性
React+TypeScript Axios客户端重构报错解决及代码优化
一、核心报错原因及解决
你遇到的Property 'get' does not exist on type '() => AxiosCacheInstance'错误,本质是两点问题:
- 重构后的
apiClient是一个函数,不是直接返回的Axios实例,你直接调用apiClient.get相当于在函数上调用实例方法,自然报错。 - 函数里用了
useNavigate这个React Hook,它只能在React组件/自定义Hook的顶层调用,不能直接在类组件(AuthService是类)里执行apiClient()获取实例,会违反Hook规则。
下面给两种可行的解决思路:
方案1:改成自定义Hook,适配React组件调用
修改api-client.ts为自定义Hook
// api-client.ts import axios from 'axios' import { setupCache } from 'axios-cache-interceptor'; import { useNavigate } from "react-router-dom"; import { useMemo } from 'react'; // 自定义Hook必须以use开头 export function useApiClient() { const navigate = useNavigate(); // 用useMemo缓存实例,避免每次调用Hook都创建新实例 const apiInstance = useMemo(() => { const axiosInstance = axios.create({ withCredentials: true, baseURL: "https://localhost:44372/api/v1/", headers: { "Content-type": "application/json" }, timeout: 60 * 1000 // 1分钟超时 }); axiosInstance.interceptors.response.use( (response) => response, (error) => { // 先判断error.response是否存在,避免网络错误/超时导致的报错 if (error.response) { switch (error.response.status) { case 401: // 处理未授权逻辑,比如跳登录页 break; case 403: navigate("/status/403"); // 建议改成403专属页面,而非404 break; case 500: // 处理服务器内部错误,比如提示用户 break; } } return Promise.reject(error); } ); return setupCache(axiosInstance); }, [navigate]); return apiInstance; }
修改AuthService为Hook风格
// auth-service.ts import { useApiClient } from "./api-client"; export function useAuthService() { const apiClient = useApiClient(); return { getLoggedInUser: () => apiClient.get(`/Authorization/GetLoggedInUser`), getLoggedInUserRoles: () => apiClient.get(`/Authorization/GetSecurityAttributesAsync`), testAuthorized: () => apiClient.get('/Authorization/TestAuthorized'), testUnauthorized: () => apiClient.get('/Authorization/TestUnauthorized') }; }
在React组件中使用
// 示例组件 import { useAuthService } from './auth-service'; function UserProfile() { const authService = useAuthService(); const fetchUserInfo = async () => { try { const res = await authService.getLoggedInUser(); // 处理返回数据 } catch (err) { // 处理请求错误 } }; return <button onClick={fetchUserInfo}>获取用户信息</button>; }
方案2:不使用Hook,用全局history对象跳转
如果不想改动现有的AuthService类结构,可以用history包创建全局路由对象,替代useNavigate:
创建全局history.ts
// history.ts import { createBrowserHistory } from 'history'; export const history = createBrowserHistory();
修改api-client.ts
// api-client.ts import axios from 'axios' import { setupCache } from 'axios-cache-interceptor'; import { history } from './history'; const axiosInstance = axios.create({ withCredentials: true, baseURL: "https://localhost:44372/api/v1/", headers: { "Content-type": "application/json" }, timeout: 60 * 1000 }); axiosInstance.interceptors.response.use( (response) => response, (error) => { if (error.response) { switch (error.response.status) { case 401: // 处理未授权逻辑 break; case 403: history.push("/status/403"); break; case 500: // 处理服务器错误 break; } } return Promise.reject(error); } ); export const apiClient = setupCache(axiosInstance); export { CanceledError } from 'axios';
修改Router配置
// App.tsx import { Router } from 'react-router-dom'; import { history } from './history'; // 导入你的路由组件 import { RoutesConfig } from './routes'; function App() { return ( <Router history={history}> <RoutesConfig /> </Router> ); }
这样你的原AuthService类就可以正常使用,不用做任何修改。
二、其他代码问题提示
- 原api-client-old.ts的致命错误:在模块顶层直接调用
useNavigate(),这违反了React Hook规则,Hook只能在组件或自定义Hook的顶层调用,运行时必然报错,只是你之前可能没触发到这部分逻辑。 - 错误处理的漏洞:没有判断
error.response是否存在,当请求超时、断网时,error.response是undefined,此时访问error.response.status会直接崩溃,必须先加判断。 - 403跳转逻辑不合理:403是权限不足,跳转到404页面会误导用户,建议改成403专属提示页或登录页。
- 实例重复创建问题:如果用方案1的自定义Hook,一定要用
useMemo缓存Axios实例,否则每次组件渲染都会创建新实例和拦截器,造成性能浪费。
内容的提问来源于stack exchange,提问作者Chris Fink
相关产品推荐
相关产品推荐

