Redux自定义中间件dispatch异步logout触发最大调用栈溢出问题排查
栈溢出的根本原因
你遇到的无限递归问题,本质是中间件逻辑形成了自循环触发:
- 当前
handleAction中间件没有做去重拦截,只要满足“存在过期token、用户信息存在”的判断条件,就会调用store.dispatch(logoutAction()) - 所有dispatch出去的action,都会重新经过整个中间件链——包括logout流程内部触发的各类同步/异步action。在logout逻辑还没完成本地token清除、用户状态重置的时间差里,判断条件会一直为真,就会反复触发logout的dispatch,直到调用栈被占满抛出栈溢出错误。
- 额外的顺序问题:当前
applyMiddleware(thunk, handleAction)的注册顺序,意味着thunk在中间件链的最外层。你的logout是异步thunk形式,这类函数类型的action会直接被thunk拦截执行,根本不会传到内层的handleAction做判断,反而thunk执行logout过程中触发的各类同步action,会反复回到判断分支,进一步放大循环问题。
具体修复点
- 增加防重入标记:一旦触发过过期登出逻辑,立刻拦截后续的重复判断,避免循环触发
- 调整中间件注册顺序:把
handleAction移到thunk外层,保证不管是普通对象action还是thunk异步action,都能第一时间经过过期判断逻辑 - 明确标记重置时机:等logout流程完全执行完(本地token清除、用户状态重置完成),再把防重入标记改回初始值,避免影响后续的正常过期判断
修复后参考代码
// 模块级防重入标记,避免重复触发登出 let isLogoutTriggeredByExpire = false; const handleAction = (store) => (next) => (action) => { // 已经触发过期登出流程时,跳过重复判断 if (!isLogoutTriggeredByExpire) { const token = loadState(TOKEN); const { userAccount } = store.getState(); if (token && userAccount.email) { const decodedJwt = jwt_decode(token); if (decodedJwt.exp < dayjs().unix()) { isLogoutTriggeredByExpire = true; store.dispatch(logoutAction()); } } } // 处理登出完成的动作时,重置防重入标记 if (action.type === 'LOGOUT_SUCCESS') { isLogoutTriggeredByExpire = false; } return next(action); }; export function configureStore(initState = {}) { const store = createStore( rootReducer, initState, // 调整顺序:handleAction在外层,优先处理所有action类型 composeEnhancers(applyMiddleware(handleAction, thunk)) ); return store; }
内容的提问来源于stack exchange,提问作者Sujay Prabhu
相关产品推荐
相关产品推荐

