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); };
关键注意事项
- Hook调用规则:永远不要在普通函数、循环、条件判断里调用Hook,只能在函数组件顶层或自定义Hook(命名以
use开头)里使用。 - Axios响应结构:Axios的响应内容都包裹在
response.data里,直接用response.success是错误的。 - 跨域头设置:
Access-Control-Allow-Origin是后端需要设置的响应头,前端请求不需要添加这个字段。
内容的提问来源于stack exchange,提问作者Sabith
相关产品推荐
相关产品推荐

