Fixing Redux Persist Errors: Handling Non-Serializable Values
As a developer working with Redux and Redux Toolkit, you may have encountered the error “A non-serializable value was detected in an action”. This error typically occurs when trying to store non-serializable data in your Redux state using Redux Persist. Let’s dive into what causes this error and how to fix it.
Understanding the Error
The error looks like this:
index.js:1446 A non-serializable value was detected in an action, in the path: `register`. Value: ƒ register(key) {
_pStore.dispatch({
type: _constants__WEBPACK_IMPORTED_MODULE_2__[“REGISTER”],
key: key
});
}
The error occurs when Redux Persist tries to serialize your state during persistence or rehydration. By default, Redux Toolkit includes a serializable check middleware that prevents non-serializable values from being stored in the state.
Common Causes
There are several reasons why this error might occur:
1. Using non-serializable values in your state (like functions or undefined)
2. Including actions or reducers in your state
3. Using complex objects or functions as keys in your state
Solution
The most straightforward way to fix this error is to disable the serializable check middleware like this in your redux store:
import { configureStore } from '@reduxjs/toolkit';
import { persistReducer } from 'redux-persist';
const persistConfig = {
key: 'root',
storage: storage,
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
export default configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
However, this solution did not work for me. To fix this error, I modified my Redux Toolkit configuration to exclude certain actions from the serializable check. Here’s how you can do it:
import { configureStore, createReducer } from '@reduxjs/toolkit';
import { errorLoggingMiddleware } from '@app/store/middlewares/errorLogging.middleware';
import rootReducer from '@app/store/slices';
import { apiSlice } from '@app/slices/apiSlice';
import authReducer from '@app/slices/authSlice';
import { FLUSH, PAUSE, PERSIST, persistReducer, PURGE, REGISTER, REHYDRATE } from 'redux-persist';
import * as authActions from '@app/slices/authSlice';
import storage from 'redux-persist/lib/storage';
const persistConfig = {
key: 'root',
storage,
};
const persistedReducer = persistReducer(persistConfig, authReducer);
const apiMiddleware = apiSlice.middleware;
const combinedReducers = {
...rootReducer,
[apiSlice.reducerPath]: apiSlice.reducer,
auth: persistedReducer,
};
export const store = configureStore({
reducer: combinedReducers,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredPaths: ['pwa.event'],
ignoredActions: ['pwa/addDeferredPrompt', FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}).concat(errorLoggingMiddleware)
.concat(apiMiddleware),
devTools: true
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
What does the solution do?
1. The `ignoredActions` array in the `serializableCheck` configuration tells Redux Toolkit to ignore certain actions during the serializable check.
2. We’re ignoring the standard Redux Persist actions (`FLUSH`, `REHYDRATE`, `PAUSE`, `PERSIST`, `PURGE`, `REGISTER`) along with any potential custom actions related to Redux Persist.
Conclusion
By applying these changes to your Redux Toolkit configuration, you should be able to resolve the non-serializable value error when using Redux Persist. This solution maintains the benefits of Redux Toolkit’s built-in middleware while allowing Redux Persist to work seamlessly with your application.
Remember, while this solution resolves the immediate error, it’s crucial to maintain a clean and serializable state structure throughout your application. Happy coding!