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

如何在Axios拦截器中正确使用useNavigate?解决无效Hook调用报错

解决Axios拦截器中使用useNavigate导致的Hook调用错误

问题场景

我为服务创建了Axios响应拦截器,想在特定API调用失败(比如500状态)时跳转到错误组件,但运行时抛出错误:
Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

相关代码

agent.ts

axios.defaults.baseURL = "https://localhost:5001/api/";

const responseBody = (response: AxiosResponse) => response.data;

axios.interceptors.response.use(
  (response) => {
    return response;
  },
  (error: AxiosError) => {
    const { data, status }: { data: any; status: any } = error.response!;
    const navigate = useNavigate();
    switch (status) {
      case 500:
        //toast.error(data.title);
        navigate("server-error");
        break;
      default:
        break;
    }
    return Promise.reject(error.response);
  }
);

const request = {
  get: (url: string) => axios.get(url).then(responseBody),
};

const Catalog = {
  list: () => request.get("products"),
};

const agent = {
  Catalog,
};

组件调用代码

useEffect(() => {
  agent.Catalog.list().then((products) => setProducts(products));
}, []);

错误原因

useNavigate是React Router提供的Hook,必须在函数组件的顶层作用域或者自定义Hook内部调用。而Axios拦截器是在组件外部定义的普通函数,不属于React的组件渲染流程,直接在这里调用Hook违反了React的Hook规则,所以触发了报错。

解决方案

方案一:组件内处理错误导航

把导航逻辑移到请求调用的catch回调中,同时简化Axios拦截器的职责:

  1. 修改agent.ts的拦截器,只负责传递错误:
axios.defaults.baseURL = "https://localhost:5001/api/";

const responseBody = (response: AxiosResponse) => response.data;

axios.interceptors.response.use(
  (response) => response,
  (error: AxiosError) => {
    // 仅传递错误,导航逻辑移至组件内处理
    return Promise.reject(error.response);
  }
);

const request = {
  get: (url: string) => axios.get(url).then(responseBody),
};

const Catalog = {
  list: () => request.get("products"),
};

const agent = {
  Catalog,
};
  1. 在组件中处理错误并导航:
import { useNavigate } from "react-router-dom";

// 组件内部
const navigate = useNavigate();

useEffect(() => {
  agent.Catalog.list()
    .then((products) => setProducts(products))
    .catch((error) => {
      if (error?.status === 500) {
        navigate("server-error");
      }
    });
}, [navigate]);

方案二:封装自定义Hook统一处理错误

如果需要全局统一的错误导航逻辑,可以封装一个自定义Hook,既遵守Hook规则又复用逻辑:

  1. 创建自定义Hook useAgent.ts:
import { useNavigate } from "react-router-dom";
import agent from "../agent";

export const useAgent = () => {
  const navigate = useNavigate();

  // 统一错误处理函数
  const handleError = (error: any) => {
    if (error?.status === 500) {
      navigate("server-error");
    }
    return Promise.reject(error);
  };

  // 封装带错误处理的请求方法
  const Catalog = {
    list: () => agent.Catalog.list().catch(handleError),
  };

  return { Catalog };
};
  1. 在组件中使用该Hook:
import { useAgent } from "./hooks/useAgent";

// 组件内部
const { Catalog } = useAgent();

useEffect(() => {
  Catalog.list().then((products) => setProducts(products));
}, []);

方案三:使用历史对象(适配React Router v5或全局导航场景)

如果使用React Router v5,或者必须在非组件环境实现导航,可以创建独立的history实例:

  1. 创建history.ts文件:
import { createBrowserHistory } from "history";
export const history = createBrowserHistory();
  1. 在agent.ts中导入并使用:
import { history } from "./history";

axios.interceptors.response.use(
  (response) => response,
  (error: AxiosError) => {
    const { status } = error.response!;
    if (status === 500) {
      history.push("server-error");
    }
    return Promise.reject(error.response);
  }
);

注意:React Router v6官方推荐使用useNavigate,此方案更适合v5或特殊全局导航需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 03:30:51