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

React高阶组件(HOC)中如何使用history.push?Axios拦截器跳转问题求助

我来帮你解决这个Axios拦截器HOC里无法跳转页面的问题~

问题原因分析

你的HOC里拿到的props是空对象,核心原因是:被HOC包裹的App组件没有直接被react-router的<Route>组件渲染,所以它不会自动获得history、location这些路由相关的props,导致HOC里拿不到props.history。

另外还要注意一个隐藏坑:你的useEffect没有清理逻辑,每次组件挂载都会新增一个Axios拦截器,多次挂载后会出现重复执行错误处理逻辑的问题,这个后面会一起解决。


解决方案

下面给你三种可行的解决方式,你可以根据项目的React Router版本选择:

方案1:用withRouter包装HOC(React Router v5及以下适用)

从react-router-dom导入withRouter,它可以给组件注入路由相关的props。你可以选择包装HOC内部的组件,或者包装最终导出的App组件:

修改HOC代码:

import React, { useEffect } from "react";
import axios from "axios";
import { withRouter } from "react-router-dom"; // 导入withRouter

const checkRequests = Wrapped => {
  function CheckRequests(props) {
    useEffect(()=>{
      // 保存拦截器实例,方便后续清理
      const interceptor = axios.interceptors.response.use(
        response => response,
        error => {
          if (error.response?.status === 404) {
            props.history.push('/login');
            store.dispatch(logout()); // 执行你的登出action
          }
          return Promise.reject(error);
        }
      );

      // 组件卸载时移除拦截器,避免重复添加
      return () => axios.interceptors.response.eject(interceptor);
    }, [props.history]); // 依赖history,避免不必要的重渲染

    return <Wrapped {...props} />;
  }

  // 用withRouter包装CheckRequests,注入路由props
  return withRouter(CheckRequests);
};

export default checkRequests;

或者修改App.js的导出:

import React from "react"
import CheckRequests from "./HOC/CheckRequests"
import { withRouter } from "react-router-dom";

function App(props){
  // ...你的组件逻辑
}

// 用withRouter包裹最终的组件
export default withRouter(checkRequests(App));

方案2:使用useNavigate/useHistory钩子(React Router v6+推荐)

React Router v6移除了withRouter,推荐使用路由钩子。直接在HOC的函数组件里使用useNavigate(v6)或useHistory(v5):

React Router v6版本代码:

import React, { useEffect } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom"; // v6用useNavigate

const checkRequests = Wrapped => {
  function CheckRequests(props) {
    const navigate = useNavigate(); // 获取导航方法

    useEffect(()=>{
      const interceptor = axios.interceptors.response.use(
        response => response,
        error => {
          if (error.response?.status === 404) {
            navigate('/login'); // 跳转到登录页
            store.dispatch(logout());
          }
          return Promise.reject(error);
        }
      );

      return () => axios.interceptors.response.eject(interceptor);
    }, [navigate]); // 依赖navigate

    return <Wrapped {...props} />;
  }

  return CheckRequests;
};

export default checkRequests;

方案3:创建全局history实例(无版本限制)

如果你不想依赖组件的props或钩子,可以自己创建一个全局的history实例,在路由配置和拦截器里共用:

  1. 先安装history包(React Router v6已内置,v5需要手动安装):
npm install history
  1. 创建history.js文件:
// history.js
import { createBrowserHistory } from 'history';

export const history = createBrowserHistory();
  1. 修改路由配置(比如index.js):
import { Router } from 'react-router-dom';
import { history } from './history';

ReactDOM.render(
  <Router history={history}>
    <App />
  </Router>,
  document.getElementById('root')
);
  1. 在HOC里直接使用全局history:
import React, { useEffect } from "react";
import axios from "axios";
import { history } from '../history'; // 导入全局history

const checkRequests = Wrapped => {
  function CheckRequests(props) {
    useEffect(()=>{
      const interceptor = axios.interceptors.response.use(
        response => response,
        error => {
          if (error.response?.status === 404) {
            history.push('/login');
            store.dispatch(logout());
          }
          return Promise.reject(error);
        }
      );

      return () => axios.interceptors.response.eject(interceptor);
    }, []);

    return <Wrapped {...props} />;
  }

  return CheckRequests;
};

export default checkRequests;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 21:27:36