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

在自定义Axios服务中使用React Hook报错的解决咨询

解决React Hook在服务函数中的调用错误

React Hook的规则明确要求:只能在React函数组件或自定义React Hook中调用Hook,所以直接在auth.service.tsx这类普通服务文件里调用useAxiosPrivate肯定会报错。下面给你三种可行的解决思路:

方案一:组件内调用Hook,把axios实例传给服务方法

既然Hook只能在组件里用,那就先在需要调用服务的组件中获取axiosPrivate实例,再把它作为参数传给服务方法。

修改auth.service.tsx:

// auth.service.tsx
export const SharedService = {
  UpdateProfile: async (axiosPrivate, firstName:string, lastName:string) => {
    const response = await axiosPrivate.put('/user/me', {
      firstName,
      lastName,
    });
    return response;
  }
};

在组件中使用:

// 示例:ProfileEdit组件
import useAxiosPrivate from "../hooks/useAxiosPrivate";
import { SharedService } from "../services/auth.service";

const ProfileEdit = () => {
  const axiosPrivate = useAxiosPrivate();

  const handleUpdate = async () => {
    try {
      await SharedService.UpdateProfile(axiosPrivate, "John", "Doe");
      // 处理更新成功的逻辑
    } catch (err) {
      // 处理错误
    }
  };

  return <button onClick={handleUpdate}>更新个人资料</button>;
};

方案二:把服务封装成自定义Hook

直接把服务方法包装成一个自定义Hook,这样就能在内部合法调用其他Hook了。

新建useAuthService.tsx:

// useAuthService.tsx
import useAxiosPrivate from "../hooks/useAxiosPrivate";

const useAuthService = () => {
  const axiosPrivate = useAxiosPrivate();

  const UpdateProfile = async (firstName:string, lastName:string) => {
    const response = await axiosPrivate.put('/user/me', {
      firstName,
      lastName,
    });
    return response;
  };

  return { UpdateProfile };
};

export default useAuthService;

在组件中使用:

import useAuthService from "../hooks/useAuthService";

const ProfileEdit = () => {
  const { UpdateProfile } = useAuthService();

  const handleUpdate = async () => {
    try {
      await UpdateProfile("John", "Doe");
      // 处理成功逻辑
    } catch (err) {
      // 处理错误
    }
  };

  return <button onClick={handleUpdate}>更新个人资料</button>;
};

方案三:把拦截器逻辑移出Hook,整合到Axios实例

如果不想让服务依赖Hook,可以把token自动添加、刷新的逻辑从Hook里抽出来,直接绑定到axiosPrivate实例上,通过外部传入auth状态和refresh函数来初始化拦截器。

首先修改api/axios.ts:

// api/axios.ts
import axios from 'axios';

export const axiosPrivate = axios.create({
  baseURL: '/api',
  headers: { 'Content-Type': 'application/json' },
  withCredentials: true
});

// 定义初始化拦截器的方法
export const setupAxiosPrivateInterceptors = (auth, refresh) => {
  const requestIntercept = axiosPrivate.interceptors.request.use(
    (config) => {
      config.headers = config.headers ?? {};
      if (!config.headers['Authorization']) {
        config.headers['Authorization'] = `Bearer ${auth?.accessToken}`;
      }
      return config;
    },
    (error) => Promise.reject(error)
  );

  const responseIntercept = axiosPrivate.interceptors.response.use(
    (response) => response,
    async (error) => {
      const prevRequest = error?.config;
      if (
        (error?.response?.status === 403 || error?.response?.status === 401) &&
        !prevRequest?.sent
      ) {
        prevRequest.sent = true;
        const newAccessToken = await refresh();
        prevRequest.headers['Authorization'] = `Bearer ${newAccessToken}`;
        return axiosPrivate(prevRequest);
      }
      return Promise.reject(error);
    }
  );

  return () => {
    axiosPrivate.interceptors.request.eject(requestIntercept);
    axiosPrivate.interceptors.response.eject(responseIntercept);
  };
};

然后修改原useAxiosPrivate.tsx(用来在组件中初始化拦截器):

// useAxiosPrivate.tsx
import { axiosPrivate, setupAxiosPrivateInterceptors } from '../api/axios';
import { useEffect } from 'react';
import useRefreshToken from './useRefreshToken';
import useAuth from './useAuth';

const useAxiosPrivate = () => {
  const refresh = useRefreshToken();
  const { auth }: any = useAuth();

  useEffect(() => {
    const cleanup = setupAxiosPrivateInterceptors(auth, refresh);
    return cleanup;
  }, [auth, refresh]);

  return axiosPrivate;
};

export default useAxiosPrivate;

最后修改auth.service.tsx,直接使用axiosPrivate:

// auth.service.tsx
import { axiosPrivate } from "../api/axios";

export const SharedService = {
  UpdateProfile: async (firstName:string, lastName:string) => {
    const response = await axiosPrivate.put('/user/me', {
      firstName,
      lastName,
    });
    return response;
  }
};

注意:这种方式要确保调用服务方法前,已经有组件调用过useAxiosPrivate初始化拦截器,否则请求不会自动处理token。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 09:20:38