You need to enable JavaScript to run this app. Redux自定义中间件dispatch异步logout触发最大调用栈溢出问题排查
优惠活动
大模型
产品
解决方案
定价
更多

Redux自定义中间件dispatch异步logout触发最大调用栈溢出问题排查

栈溢出的根本原因

你遇到的无限递归问题,本质是中间件逻辑形成了自循环触发:

  1. 当前handleAction中间件没有做去重拦截,只要满足“存在过期token、用户信息存在”的判断条件,就会调用store.dispatch(logoutAction())
  2. 所有dispatch出去的action,都会重新经过整个中间件链——包括logout流程内部触发的各类同步/异步action。在logout逻辑还没完成本地token清除、用户状态重置的时间差里,判断条件会一直为真,就会反复触发logout的dispatch,直到调用栈被占满抛出栈溢出错误。
  3. 额外的顺序问题:当前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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 19:45:08