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

React Redux报错:Invalid hook call,求解决401登出逻辑问题

解决React/Redux中调用Hook出现的"Invalid hook call"错误

错误原因

你遇到的问题核心是违反了React Hook的调用规则:useDispatch、useNavigate这类Hook只能在函数组件的顶层或者以"use"开头的自定义Hook里调用。你写的Logout是普通函数,直接调用Logout().logout()时,里面的Hook在普通函数内部执行,自然触发报错。

解决方案

方式一:直接使用Redux Store实例和原生导航(适合新手快速解决)

跳过Hook,直接用Redux的Store实例更新状态,用原生window.location跳转登录页,这样在service文件的普通函数里就能正常执行。

步骤1:导出Redux Store实例

确保你的Redux Store配置文件(比如Store/store.js)导出store对象:

// Store/store.js
import { configureStore } from '@reduxjs/toolkit';
import storeSlice from './storeSlice';

export const store = configureStore({
  reducer: {
    auth: storeSlice,
  },
});

步骤2:修改Service文件代码

替换原代码,去掉Hook导入,改用Store实例和原生导航:

import axios from "axios";
import { endPoints } from "./endPoints";
import { updateAuth } from "../Store/storeSlice";
import { store } from "../Store/store"; // 导入Store实例

export const getIncidentData = async (query, authToken) => {
  return await getData(endPoints.getIncidents + query, authToken);
};

// 直接定义logout函数,无需组件或Hook
const logout = () => {
  // 用store实例调用dispatch清空token
  store.dispatch(updateAuth({ authToken: "" }));
  // 原生跳转登录页
  window.location.href = "/Login";
};

const getData = async (url, authToken) => {
  try {
    const response = await axios({
      method: "get",
      url: endPoints.baseUrl + url,
      headers: {
        "x-access-token": authToken,
        "Content-Type": "application/json",
        "X-AUTH-TOKEN": authToken,
      },
    });

    // Axios的响应数据存在response.data里,注意修正取值路径
    if (response.data.success) {
      return response.data;
    }
    if (response.data.errorCode === 401) {
      logout();
    }
    return response.data;
  } catch (error) {
    if (error.response?.data?.errorCode === 401) {
      logout();
    }
    // 优化错误信息处理逻辑
    const message = error?.code !== "ERR_NETWORK"
      ? error?.response?.statusText || "请求错误"
      : "网络错误";
    return {
      success: false,
      message,
      status: error?.response?.status || 500,
    };
  }
};

方式二:用Axios拦截器统一处理401(更优雅的方案)

用Axios拦截器统一处理所有请求的token注入和401错误,避免重复代码:

import axios from "axios";
import { endPoints } from "./endPoints";
import { updateAuth } from "../Store/storeSlice";
import { store } from "../Store/store";

// 创建Axios实例,统一配置baseURL
const api = axios.create({
  baseURL: endPoints.baseUrl,
  headers: {
    "Content-Type": "application/json",
  },
});

// 请求拦截器:自动给所有请求添加token
api.interceptors.request.use((config) => {
  const { authToken } = store.getState().auth;
  if (authToken) {
    config.headers["x-access-token"] = authToken;
    config.headers["X-AUTH-TOKEN"] = authToken;
  }
  return config;
});

// 响应拦截器:统一处理401错误
api.interceptors.response.use(
  (response) => response.data, // 直接返回响应数据,简化后续处理
  (error) => {
    if (error.response?.data?.errorCode === 401) {
      store.dispatch(updateAuth({ authToken: "" }));
      window.location.href = "/Login";
    }
    const message = error?.code !== "ERR_NETWORK"
      ? error?.response?.statusText || "请求错误"
      : "网络错误";
    return Promise.reject({
      success: false,
      message,
      status: error?.response?.status || 500,
    });
  }
);

// 简化接口调用,无需手动传token
export const getIncidentData = async (query) => {
  return await api.get(endPoints.getIncidents + query);
};

关键注意事项

  1. Hook调用规则:永远不要在普通函数、循环、条件判断里调用Hook,只能在函数组件顶层或自定义Hook(命名以use开头)里使用。
  2. Axios响应结构:Axios的响应内容都包裹在response.data里,直接用response.success是错误的。
  3. 跨域头设置:Access-Control-Allow-Origin是后端需要设置的响应头,前端请求不需要添加这个字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 02:25:38