Issue
So I am migrating my application to NextJS and I have the following store configuration. It's a little messy right now as I'll be cleaning up everything/reducing duplicated code once I've got it all working.
import { configureStore } from '@reduxjs/toolkit';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist';
import expireReducer from 'redux-persist-expire';
import { API } from 'utils/RTKAPI';
import createSagaMiddleware from 'redux-saga';
import { createOrSyncSettings } from 'controllers/SettingsController';
import { syncWords } from 'controllers/WordController';
import { syncSentences } from 'controllers/SentenceController';
import { syncBookmarks } from 'controllers/BookmarkController';
import { syncReadArticles } from 'controllers/ReadArticleController';
import rootSaga from 'reducers/sagas/index';
import moment from 'moment';
import { createWrapper, HYDRATE } from 'next-redux-wrapper';
import rootReducer from 'reducers/rootReducer';
const makeStore = () => {
const SSR = typeof window === 'undefined';
if (SSR) {
const sagaMiddleware = createSagaMiddleware();
const store = configureStore({
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}).concat(
loggerMiddleware,
promiseMiddleware,
sagaMiddleware,
syncMiddleware,
API.middleware
),
reducer: rootReducer(),
});
sagaMiddleware.run(rootSaga);
return store;
} else {
const { persistStore, persistReducer } = require('redux-persist');
const sagaMiddleware = createSagaMiddleware();
const persistConfig = {
key: 'root',
storage: AsyncStorage,
blacklist: [API.reducerPath, 'router', 'sidebar', 'currentchar'],
transforms: [
expireReducer('date', {
expireSeconds: 86400,
expiredState: {
end_date: moment().format('YYYY-MM-DD'),
start_date: '2021-07-04',
},
autoExpire: true,
}),
],
};
const persistedReducer = persistReducer(persistConfig, rootReducer());
const store = configureStore({
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}).concat(
loggerMiddleware,
promiseMiddleware,
sagaMiddleware,
syncMiddleware,
API.middleware
),
reducer: persistedReducer,
});
sagaMiddleware.run(rootSaga);
store.__persistor = persistStore(store); // Necessary hack
return store;
}
};
export const wrapper = createWrapper(makeStore);
async function callSync(store) {
const storeState = await store.getState();
const profile = storeState.profile;
if (profile !== null) {
createOrSyncSettings(profile.id);
syncWords(profile);
syncSentences(profile);
syncBookmarks(profile);
syncReadArticles(profile);
}
}
const loggerMiddleware = (store) => (next) => (action) => {
next(action);
};
function promiseMiddleware({ dispatch }) {
function isPromise(val) {
return val && typeof val.then === 'function';
}
return (next) => (action) => {
return isPromise(action.payload)
? action.payload.then(
(result) => dispatch({ ...action, payload: result }),
(error) => dispatch({ ...action, payload: error, error: true })
)
: next(action);
};
}
const syncMiddleware = (store) => (next) => (action) => {
next(action);
if (action.type === 'persist/REHYDRATE') {
callSync(store);
}
};
My rootReducer is pretty standard too:
export default () =>
combineReducers({
[API.reducerPath]: API.reducer,
categories,
profile,
...
Yet despite my configuration, I keep getting this error:
Error: Warning: Middleware for RTK-Query API at reducerPath "api" has not been added to the store.
You must add the middleware for RTK-Query to function correctly!
What exactly am I doing wrong? As far as I can tell, my reducerPath has been added to the store.
A similar store configuration worked just fine in a previous iteration of my app, that did not use NextJS, so I am wondering what is causing the issue now.
Solution
Your hand-written Redux syncMiddleware
is broken. It doesn't return the result of next(action)
. That means that if a later middleware tries to return a value, that later return result gets thrown away and will never be returned from dispatch
.
The RTKQ configuration check relies on dispatching a special action that is intercepted by the RTKQ middleware and returning a matching result. Since your middleware is throwing away that result, the UI layer concludes that the RTKQ middleware was not actually added correctly. (And in a sense, it wasn't!)
Answered By - markerikson
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.