Environment:
redux-persist version: "^6.0.0",
@reduxjs/toolkit version:"^2.3.0",
react-redux version: "^9.1.2",
react version: "19.2.0",
Description:
When using persistReducer as a nested slice (not root reducer) inside a large RTK configureStore that contains many RTK Query API reducers, and using PersistGate with persistStore(store), the app throws a stack overflow during render.
Minimal reproduction of the setup:
tabs.util.ts — persisted slice definition:
typescriptimport { combineReducers } from '@reduxjs/toolkit';
import { persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import tabsReducer from './tabs.slice';
const rootReducer = combineReducers({ tabs: tabsReducer });
const persistConfig = { key: 'tabs-core', storage };
export const persistedReducer = persistReducer(persistConfig, rootReducer);
2) shared-common-apps-store.ts — nested inside main store:
typescriptexport const sharedCommonAppsReducerStore = {
persistedReducer: persistedReducer, // ← nested persisted reducer
preservedAppIdSlice: preservedAppIdSlice.reducer,
triggerPasteReducer: triggerPasteReducer,
[personsApi.reducerPath]: personsApi.reducer,
// ... ~40 more RTK Query API reducers
};
3) store.ts — main store:
typescriptexport const store = configureStore({
reducer: {
...sharedCommonAppsReducerStore, // contains persistedReducer as nested slice
...accountingReducerStore,
...treasuryReducerStore,
...generalReducerStore,
...sharedServiceReducerStore,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware()
.prepend(listenerMiddleware.middleware)
.concat(mergeMiddlewareStore)
.concat(rtkQueryErrorLogger),
});
4) SharedProviders.tsx — PersistGate usage:
tsxexport function SharedProviders({ theme, children, store }) {
const persistor = persistStore(store); // called on the main store
return (
{children}
);
}
5) App.tsx — entry point:
tsxexport function App() {
const theme = useMemo(() => createSharedTheme(), []);
return (
);
}
Error:
RangeError: Maximum call stack size exceeded
at actuallyMutateSubscriptions (chunk-JVMNWONT.js:2000:39)
at chunk-JVMNWONT.js:2089:23
at chunk-JVMNWONT.js:2717:61
at chunk-JVMNWONT.js:2720:17
at chunk-JVMNWONT.js:2720:17
... (repeating)
What I tried:
Moving persistStore outside of React component → same error
Using useRef(() => persistStore(store)) → same error
Adding serializableCheck ignored actions → same error
Creating a separate store just for persistStore → different error (PersistGate and Provider on different stores)
Removing persistedReducer from the store → error disappears ✅
Removing PersistGate → error disappears ✅
Question:
Is using persistReducer as a nested slice (not root reducer) with PersistGate on the main store a supported pattern? The error only appears when the store has a large number of reducers (~50+). With fewer reducers it seems to work fine.
If this pattern is not supported, what is the recommended approach for persisting only a subset of the Redux state?
Environment:
redux-persist version: "^6.0.0",
@reduxjs/toolkit version:"^2.3.0",
react-redux version: "^9.1.2",
react version: "19.2.0",
Description:
When using persistReducer as a nested slice (not root reducer) inside a large RTK configureStore that contains many RTK Query API reducers, and using PersistGate with persistStore(store), the app throws a stack overflow during render.
Minimal reproduction of the setup:
tabs.util.ts — persisted slice definition:
typescriptimport { combineReducers } from '@reduxjs/toolkit';
import { persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import tabsReducer from './tabs.slice';
const rootReducer = combineReducers({ tabs: tabsReducer });
const persistConfig = { key: 'tabs-core', storage };
export const persistedReducer = persistReducer(persistConfig, rootReducer);
2) shared-common-apps-store.ts — nested inside main store:
typescriptexport const sharedCommonAppsReducerStore = {
persistedReducer: persistedReducer, // ← nested persisted reducer
preservedAppIdSlice: preservedAppIdSlice.reducer,
triggerPasteReducer: triggerPasteReducer,
[personsApi.reducerPath]: personsApi.reducer,
// ... ~40 more RTK Query API reducers
};
3) store.ts — main store:
typescriptexport const store = configureStore({
reducer: {
...sharedCommonAppsReducerStore, // contains persistedReducer as nested slice
...accountingReducerStore,
...treasuryReducerStore,
...generalReducerStore,
...sharedServiceReducerStore,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware()
.prepend(listenerMiddleware.middleware)
.concat(mergeMiddlewareStore)
.concat(rtkQueryErrorLogger),
});
4) SharedProviders.tsx — PersistGate usage:
tsxexport function SharedProviders({ theme, children, store }) {
const persistor = persistStore(store); // called on the main store
return (
{children}
);
}
5) App.tsx — entry point:
tsxexport function App() {
const theme = useMemo(() => createSharedTheme(), []);
return (
);
}
Error:
RangeError: Maximum call stack size exceeded
at actuallyMutateSubscriptions (chunk-JVMNWONT.js:2000:39)
at chunk-JVMNWONT.js:2089:23
at chunk-JVMNWONT.js:2717:61
at chunk-JVMNWONT.js:2720:17
at chunk-JVMNWONT.js:2720:17
... (repeating)
What I tried:
Moving persistStore outside of React component → same error
Using useRef(() => persistStore(store)) → same error
Adding serializableCheck ignored actions → same error
Creating a separate store just for persistStore → different error (PersistGate and Provider on different stores)
Removing persistedReducer from the store → error disappears ✅
Removing PersistGate → error disappears ✅
Question:
Is using persistReducer as a nested slice (not root reducer) with PersistGate on the main store a supported pattern? The error only appears when the store has a large number of reducers (~50+). With fewer reducers it seems to work fine.
If this pattern is not supported, what is the recommended approach for persisting only a subset of the Redux state?