使用Redux Toolkit与createAsyncThunk时出现baseReducer非函数错误
我使用 Redux-Toolkit 从 MSAL 获取 accessToken,并用 Redux-Persist 将 Store 持久化到 localStorage。客户端列表页可正常获取搜索结果,此前页面刷新也无异常,但近期突然抛出错误:
Error in function eval in ./node_modules/redux-persist/es/persistReducer.js:144 baseReducer is not a function
相关代码如下:
store.js
import { configureStore } from '@reduxjs/toolkit' import usersReducer from "./userSlice"; import storage from 'redux-persist/lib/storage'; import { persistReducer, persistStore } from 'redux-persist'; const persistConfig = { key: 'root', storage, } const persistedReducer = persistReducer(persistConfig, usersReducer) export const store = configureStore( { reducer: { users: persistedReducer, } }) export const persistor = persistStore(store)
userSlice.js
import { useMsal } from "@azure/msal-react"; import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { loginRequest } from "./authConfig"; import { msalInstance } from "./pages/index"; export const fetchUsersToken = createAsyncThunk( "users/fetchUsersToken", async (dispatch, getState) => { try { const token = await msalInstance.acquireTokenSilent(dispatch) .then((data) => data.accessToken) return token } catch (error) { return error.response.data } } ); const usersSlice = createSlice({ name: "users", initialState: { users: null, loading: true }, reducers: {}, extraReducers(builder) { builder .addCase(fetchUsersToken.pending, (state, action) => { state.loading = true }) .addCase(fetchUsersToken.fulfilled, (state, action) => { state.loading = false, state.users = action.payload }) .addCase(fetchUsersToken.rejected, (state, action) => { state.loading = false }); } }) export default usersSlice.reducer;
Layout 组件 index.js
import React from "react" import { Provider, useDispatch } from "react-redux"; import {persistor, store} from "../../store"; import Footer from "../Footer" import { createTheme, ThemeProvider } from "@mui/material/styles" import { PersistGate } from 'redux-persist/integration/react'; const theme = createTheme({ palette: { primary: { main: "#000000" }, }, }) const Layout = ({ children }) => ( <div> <ThemeProvider theme={theme}> <Provider store={store}> <PersistGate loading={null} persistor={persistor}> {children} <Footer/> </PersistGate> </Provider> </ThemeProvider> </div> ) export default Layout
LandingPage.js(分发 action 处)
const request = { ...loginRequest, account: accounts[0] } store.dispatch(fetchUsersToken(request))
MSAL 初始化 index.js
import React from "react" import { Helmet } from "react-helmet" import { PublicClientApplication } from "@azure/msal-browser" import { MsalProvider, useMsal } from "@azure/msal-react" import { loginRequest, msalConfig } from "../authConfig" import PageLayout from "../components/PageLayout" import App from "./app" import Layout from "../components/Layout" import { Provider, useDispatch } from "react-redux"; import {store} from "../store"; export const msalInstance = new PublicClientApplication(msalConfig) export default function Home() { return ( <> <Helmet> <title>Client Engagement Lookup</title> </Helmet> <MsalProvider instance={msalInstance}> <Layout> <PageLayout /> </Layout> </MsalProvider> </> ) }
问题排查与修复
1. AsyncThunk 参数定义错误
fetchUsersToken 的参数顺序完全写反了:createAsyncThunk 的 payload creator 函数,第一个参数是dispatch 时传入的请求参数,第二个才是包含 dispatch、getState 的 thunkAPI 对象。当前错误的参数传递会导致 MSAL 获取 token 时传入无效值,进而引发状态异常,最终触发持久化时的 reducer 错误。
修正后的 fetchUsersToken:
export const fetchUsersToken = createAsyncThunk( "users/fetchUsersToken", async (requestParams, { rejectWithValue }) => { try { const data = await msalInstance.acquireTokenSilent(requestParams); return data.accessToken; } catch (error) { return rejectWithValue(error.response?.data || error.message); } } );
2. 清除旧持久化数据
如果 localStorage 中存储的旧数据结构与当前 reducer 的状态结构不兼容,也会导致 redux-persist 恢复状态时出错。可以手动清除浏览器 localStorage 中的 persist:root 条目,再测试页面刷新是否正常。
3. 确保 Redux Provider 唯一
检查应用中是否存在多个 Redux Provider 嵌套的情况(当前代码中已注释掉重复的 Provider,但需保持全局仅一个 Provider 实例),避免 Store 实例混乱引发异常。
4. 版本兼容性检查
确保 @reduxjs/toolkit 和 redux-persist 版本兼容,可尝试更新至最新稳定版:
npm update @reduxjs/toolkit redux-persist
额外优化
- 在
fetchUsersToken.rejected分支中添加错误状态存储,方便调试:
.addCase(fetchUsersToken.rejected, (state, action) => { state.loading = false; state.error = action.payload; });
- 组件内建议使用
useDispatchHook 而非直接调用store.dispatch,比如 LandingPage.js 中:
import { useDispatch } from 'react-redux'; import { fetchUsersToken } from '../userSlice'; // 组件内部 const dispatch = useDispatch(); const request = { ...loginRequest, account: accounts[0] }; dispatch(fetchUsersToken(request));
内容的提问来源于stack exchange,提问作者Lakshmi

