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

在Next.js中用Redux Toolkit集成Mutex时出现getState未定义错误

解决Next.js + Redux Toolkit Query + async-mutex 中的 getState 未定义错误

问题原因

该错误的核心是循环依赖或baseQuery包装函数参数传递错误:

  • 若store与api存在循环导入,会导致api初始化时store上下文未就绪;
  • 若重鉴权的baseQuery包装函数未正确接收api参数,调用api.getState()时就会出现undefined。

解决方案

1. 正确实现带重鉴权的baseQuery并使用mutex

重构api文件,确保mutex实例化、baseQuery包装逻辑正确,且不直接导入store:

import { Mutex } from 'async-mutex';
import { fetchBaseQuery, createApi } from '@reduxjs/toolkit/query/react';
import { BASE_API_V1 } from './constants';

// 实例化mutex,确保作用域在api创建之前
const mutex = new Mutex();

// 基础fetch查询配置
const baseQuery = fetchBaseQuery({ baseUrl: BASE_API_V1 });

// 带自动重鉴权的baseQuery包装函数
const baseQueryWithReauth = async (args, api, extraOptions) => {
  // 先执行正常请求
  let result = await baseQuery(args, api, extraOptions);

  // 捕获401过期错误,触发重鉴权逻辑
  if (result.error && result.error.status === 401) {
    // 确保同一时间只有一个刷新请求执行
    if (!mutex.isLocked()) {
      const releaseLock = await mutex.acquire();
      try {
        // 通过api参数获取当前state,避免直接导入store
        const { auth } = api.getState();
        // 调用刷新token的接口(需提前在endpoints中定义refreshToken)
        const refreshResponse = await api.dispatch(
          api.endpoints.refreshToken.initiate({ refreshToken: auth.refreshToken })
        );

        if (refreshResponse.data) {
          // 刷新成功后重新执行原请求
          result = await baseQuery(args, api, extraOptions);
        } else {
          // 刷新失败,执行登出/跳转登录页逻辑
          // window.location.href = '/login';
        }
      } finally {
        // 释放mutex锁
        releaseLock();
      }
    } else {
      // 已有刷新请求在执行,等待锁释放后重试
      await mutex.waitForUnlock();
      result = await baseQuery(args, api, extraOptions);
    }
  }

  return result;
};

// 创建RTK Query API实例
export const api = createApi({
  reducerPath: 'api',
  baseQuery: baseQueryWithReauth,
  endpoints: (builder) => ({
    // 在这里定义你的接口endpoint
    // 示例:getUser: builder.query({ query: (id) => `/users/${id}` })
  })
});

2. 确保store初始化顺序,避免循环依赖

在store文件中,确保先导入完全定义好的api,再创建store:

import { configureStore } from '@reduxjs/toolkit';
import { api } from './api'; // 确保api已完成定义

export const store = configureStore({
  reducer: {
    [api.reducerPath]: api.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(api.middleware),
});

3. 检查Next.js SSR上下文(若使用)

如果项目使用SSR(如getServerSideProps),需确保每个请求的store实例独立,但mutex可保持全局单例(仅用于客户端请求锁)。若服务器端也需要重鉴权,建议将mutex的实例化放在客户端专属代码中,避免SSR时的上下文冲突。

关键注意事项

  • 绝对不要直接在api文件中导入store,所有状态获取必须通过baseQuery的api.getState()方法;
  • 确保baseQuery包装函数严格接收args, api, extraOptions三个参数,缺一不可;
  • mutex的锁必须在finally块中释放,避免死锁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 05:54:56