英文:
basereducer is not a function - Redux Toolkit with createasyncthunk
问题
我正在使用redux-toolkit
从MSAL获取accessToken,并使用redux-persist
将存储在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 default usersSlice.reducer;
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';
// ...其他部分...
export default Layout;
LandingPage.js(在这里我正在分发动作)
const request = {
...loginRequest,
account: accounts[0],
};
store.dispatch(fetchUsersToken(request));
index.js(在这里初始化msalInstance)
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";
// ...其他部分...
export default function Home() {
return (
<>
<Helmet>
<title>Client Engagement Lookup</title>
</Helmet>
<MsalProvider instance={msalInstance}>
<Layout>
<PageLayout />
</Layout>
</MsalProvider>
</>
);
}
希望这些信息对你有所帮助。如果你需要更多的帮助,请随时告诉我。
英文:
I am using redux-toolkit
to acquire accessToken from MSAL and redux-persist
to persist the store in localStorage. I'm getting search results in clientlisting page. When I refresh the page it was working fine. But few minutes ago it throws me an error "Error in function eval in ./node_modules/redux-persist/es/persistReducer.js:144 baseReducer is not a function" I couldn't figure where am I doing wrong
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;
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';
// Global styles and component-specific styles.
//For changing default blue color for mui text-fields
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 ( where I'm dispatching the action.)
const request = {
...loginRequest,
account: accounts[0]
}
store.dispatch(fetchUsersToken(request))
Here is my index.js ( where msalInstance initiated )
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"
//Redux
import { Provider, useDispatch } from "react-redux";
import {store} from "../store";
//Redux Ends here
export const msalInstance = new PublicClientApplication(msalConfig)
export default function Home() {
return (
<>
<Helmet>
<title>Client Engagement Lookup</title>
</Helmet>
<MsalProvider instance={msalInstance}>
{/* <Provider store={store}> */}
<Layout>
<PageLayout />
</Layout>
{/* </Provider> */}
</MsalProvider>
</>
)
}
答案1
得分: 1
以下是您要翻译的部分:
"After copy/pasting the code you shared into a running codesandbox I wasn't able to reproduce the error you describe, but I do see some discrepancies in the code, specifically in the userSlice.js
file.
The main discrepancy I see is that the thunk is incorrectly accessing the thunkAPI
. createAsyncThunk
payload creators do take two arguments, the first is the arg
(e.g. the request
object) that is passed to the function and the second is the thunkAPI
object. Update the thunk to correctly destructure dispatch
and getState
from the thunkAPI
object.
export const fetchUsersToken = createAsyncThunk(
"users/fetchUsersToken",
async (request, { dispatch, getState }) => { // <-- destructure thunkAPI
try {
const { accessToken } = await msalInstance.acquireTokenSilent(request);
return accessToken;
} catch (error) {
return error.response.data;
}
}
);
A second discrepancy I noticed was in the fetchUsersToken.fulfilled
reducer case where a Comma operator was used between the lines to set the loading
and users
states. This doesn't really affect much though since each operand mutates the state
independently, but should still be fixed for readability's and maintenance's sake.
const usersSlice = createSlice({
name: "users",
initialState: {
users: null,
loading: true
},
extraReducers(builder) {
builder
.addCase(fetchUsersToken.pending, (state, action) => {
state.loading = true;
})
.addCase(fetchUsersToken.fulfilled, (state, action) => {
state.loading = false; // <-- own line, expression
state.users = action.payload; // <-- own line, expression
})
.addCase(fetchUsersToken.rejected, (state, action) => {
state.loading = false;
});
}
});
export default usersSlice.reducer;
英文:
After copy/pasting the code you shared into a running codesandbox I wasn't able to reproduce the error you describe, but I do see some discrepancies in the code, specifically in the userSlice.js
file.
The main discrepancy I see is that the thunk is incorrectly accessing the thunkAPI
. createAsyncThunk
payload creators do take two arguments, the first is the arg
(e.g. the request
object) that is passed to the function and the second is the thunkAPI
object. Update the thunk to correctly destructure dispatch
and getState
from the thunkAPI
object.
export const fetchUsersToken = createAsyncThunk(
"users/fetchUsersToken",
async (request, { dispatch, getState }) => { // <-- destructure thunkAPI
try {
const { accessToken } = await msalInstance.acquireTokenSilent(request);
return accessToken;
} catch (error) {
return error.response.data;
}
}
);
A second discrepancy I noticed was in the fetchUsersToken.fulfilled
reducer case where a Comma operator was used between the lines to set the loading
and users
states. This doesn't really effect much though since each operand mutates the state
independently, but should still be fixed for readability's and maintenance's sake.
const usersSlice = createSlice({
name: "users",
initialState: {
users: null,
loading: true
},
extraReducers(builder) {
builder
.addCase(fetchUsersToken.pending, (state, action) => {
state.loading = true;
})
.addCase(fetchUsersToken.fulfilled, (state, action) => {
state.loading = false; // <-- own line, expression
state.users = action.payload; // <-- own line, expression
})
.addCase(fetchUsersToken.rejected, (state, action) => {
state.loading = false;
});
}
});
export default usersSlice.reducer;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论