Closed rseemann closed 5 years ago
Are you using redux-starter-kit
? It looks like the message is caused by the included serializable-state-invariant-middleware
(https://redux-starter-kit.js.org/api/getdefaultmiddleware).
As far as I can tell, passing the register
and rehydrate
functions in the action is central to how redux-persist
currently works, but the message can be suppressed by modifying the store configuration to not include that particular middleware function.
That is exactly what is going on. Further investigating I noticed this in the default middleware. I'll just remove the middleware, since it's not really essential to what I'm doing.
Cheers!
@rseemann How exactly did you solve this? Please post your configureStore
function.
@SeedyROM I removed the getDefaultMiddleware
from the list of middlewares. There is no real fix there, it is a problem between opinions. The serializable-state-invariant-middleware
complains when it sees a non-serializable object, a function in this case, being passed as an action; redux-persist
needs to do so. Sometimes you just have to pick a side π€·ββοΈ .
Anyway, here's my configureStore
.
const store = configureStore({
reducer: rootReducer,
middleware: [thunk, logger]
})
@rseemann Where exactly are you getting thunk and logger from, I saw that in the documentation but I was a little bit lost. Did you manually configure them both?
Still a redux noob! Sorry!
@rseemann I was also having issues with PersistGate never rendering, did you run into anything of the sort? I know this probably isn't the place to ask this, but I'm sleepy and desperate.
@SeedyROM I'm using them as they come, no custom config.
import logger from 'redux-logger'
import thunk from 'redux-thunk'
You might have to install those yourself, although I believe redux-starter-kit
will have them already, I think it is better to have more atomic dependencies.
About the PersistGate error you mentioned, I never saw this, I'm sorry. Also, don't code while sleepy, man! hahaha
@rseemann I figured that was what was needed, but I wanted to make sure instead of battling against some configuration misunderstanding.
Yeah the PersistGate issue is strange, I'll figure it out in the morning. I don't normally do professional work this late, but dead lines my dude. lol (Don't worry, I'm quarantined in a feature branch haha)
Same issue for me, redux-persist
is using default redux configuration and redux-starter-kit
is waiting for a string.
It would be nice to have a property into configureStore
like persist: true
inside redux-starter-kit
and handling this error by using the immer pattern from redux-starter-kit
ty @rseemann
We're not going to modify configureStore
to offer options specific to redux-persist
. If the serializability check is an issue, you have the ability to modify the store setup by changing the included middleware to either leave it out or customize what fields it inspects.
There's a solution since redux-starter-kit@0.70
Now you can opt-out the serialization using serializableCheck
attr:
import { configureStore, getDefaultMiddleware } from 'redux-starter-kit'
// ...
export const store = configureStore({
reducer,
middleware: getDefaultMiddleware({
serializableCheck: false,
}),
})
Or, ignore a specific action type for the check:
export const store = configureStore({
reducer,
middleware: getDefaultMiddleware({
serializableCheck: {
ignoredActions: [someReduxPersistActionType]
}
}),
})
For anyone else struggling to find out what [someReduxPersistActionType]
should be, here's my redux-starter-kit
& redux-persist
config
import React from "react";
import ReactDOM from "react-dom";
import { configureStore, getDefaultMiddleware } from "redux-starter-kit";
import { Provider } from "react-redux";
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER
} from "redux-persist";
import storage from "redux-persist/lib/storage";
import { PersistGate } from "redux-persist/integration/react";
import App from "./App";
import rootReducer from "./reducers";
const persistConfig = {
key: "root",
version: 1,
storage
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
reducer: persistedReducer,
middleware: getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
}
})
});
let persistor = persistStore(store);
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById("root")
);
@aldreth Thanks for the code π
I am using redux-persist with redux toolkit. here is my store configuration.
I haven't implemented or configured store before. I intend to persist user state after login. Currently after login, if I reload app in emulator it always goes back to login screen.
is my store configured properly?
import {configureStore} from '@reduxjs/toolkit';
import authReducer from '../features/login/authSlice';
import AsyncStorage from '@react-native-community/async-storage';
import {persistReducer, persistStore} from 'redux-persist';
import {combineReducers} from 'redux';
import hardSet from 'redux-persist/lib/stateReconciler/hardSet';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const reducers = combineReducers({
auth: authReducer,
// other reducers goes here...
});
const persistConfig = {
key: 'root',
storage: AsyncStorage,
// stateReconciler: hardSet,
};
const _persistedReducer = persistReducer(persistConfig, reducers);
export const store = configureStore({
reducer: _persistedReducer,
});
export const persistor = persistStore(store);
Here in index.js, I use PersistGate
import React from 'react';
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import {store, persistor} from './src/stores/store';
import {Provider} from 'react-redux';
import {storeUser, storeRefreshToken} from './src/features/login/authSlice';
import {PersistGate} from 'redux-persist/lib/integration/react';
const RNRedux = () => (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
);
AppRegistry.registerComponent(appName, () => RNRedux);
@rikinshah23 You need to configure the store as in my comment above
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
reducer: persistedReducer,
middleware: getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
}
})
});
@aldreth Thanks I was able to solve the issue. I was directed to your solution and had help from @markerikson on a separate thread that I created.
For anyone else struggling to find out what
[someReduxPersistActionType]
should be, here's myredux-starter-kit
&redux-persist
configimport React from "react"; import ReactDOM from "react-dom"; import { configureStore, getDefaultMiddleware } from "redux-starter-kit"; import { Provider } from "react-redux"; import { persistStore, persistReducer, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER } from "redux-persist"; import storage from "redux-persist/lib/storage"; import { PersistGate } from "redux-persist/integration/react"; import App from "./App"; import rootReducer from "./reducers"; const persistConfig = { key: "root", version: 1, storage }; const persistedReducer = persistReducer(persistConfig, rootReducer); const store = configureStore({ reducer: persistedReducer, middleware: getDefaultMiddleware({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER] } }) }); let persistor = persistStore(store); ReactDOM.render( <Provider store={store}> <PersistGate loading={null} persistor={persistor}> <App /> </PersistGate> </Provider>, document.getElementById("root") );
This should be added to README
here regarding the compatibility between redux-persist
and redux-toolkit
and redux-starter-kit
, because redux-toolkit
and redux-starter-kit
are pretty commonly used.
We just added a section on this to the RTK Usage Guide page, here:
https://redux-toolkit.js.org/usage/usage-guide#use-with-redux-persist
How would something like await persistor.flush()
be called in a slice? It seems that if I import persistor from the store, the reducer no longer works.
+ import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
export const store = configureStore({
reducer: persistedReducer,
+ middleware: getDefaultMiddleware({
+ serializableCheck: {
+ ignoredActions: ["persist/PERSIST"],
},
}),
});
for me this fixed the issue.
Are there any differences between these two?
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: ["persist/PERSIST"]
}
}).concat(middleware)
});
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
}
}).concat(middleware)
});
because both works for me.
And what if we still get errors after implementing these recommendations? π The serialization error goes away but now I get:
redux-toolkit.esm.js:246 Uncaught (in promise) RangeError: Maximum call stack size exceeded
at trackProperties (redux-toolkit.esm.js:246)
as soon as I revert back to plain ol' react-redux
, this error goes away...
redux-starter-kit
getDefaultMiddleware() has now moved to @reduxjs/toolkit, and could be used by getting it in the argument of the callback function like this
export const store = configureStore({ reducer: persistedReducer, middleware: getDefaultMiddleware => getDefaultMiddleware({ serializableCheck: { ignoreActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }), });
redux-starter-kit
getDefaultMiddleware() has now moved to @reduxjs/toolkit, and could be used by getting it in the argument of the callback function like this
export const store = configureStore({ reducer: persistedReducer, middleware: getDefaultMiddleware => getDefaultMiddleware({ serializableCheck: { ignoreActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }), });
Thanks! Just a comment: correct arg is ignoredActions
(more info: link).
export const store = configureStore({ middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false, }), redutor: { user: persistedReducer, }, });
Hello! My problem is that the data is not saved to localStorage. Use RTK Query. Plese help me. My stor import { combineSlices, configureStore } from '@reduxjs/toolkit'; import { setupListeners } from '@reduxjs/toolkit/query'; import { postsApi } from '../redux/PostsSlice'; import { userApi } from '../redux/UserSlice'; import { persistStore, persistReducer, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER, } from 'redux-persist'; import storage from 'redux-persist/lib/storage';
const userPersistConfig = { key: 'user', storage, whitelist: ['user'], blacklist: [postsApi.reducerPath, userApi.reducerPath], };
const rootReducer = combineSlices({
[userApi.reducerPath]: persistReducer(userPersistConfig, userApi.reducer), });
export const store = configureStore({ reducer: rootReducer, middleware: getDefaultMiddleware => [ ...getDefaultMiddleware({ serializableCheck: { ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], }, }), postsApi.middleware, userApi.middleware, ], devTools: process.env.NODE_ENV !== 'production', });
setupListeners(store.dispatch); export const persistor = persistStore(store);
My Slice import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const userApi = createApi({ reducerPath: 'user',
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:4000/api/users' }),
tagTypes: ['Users'],
endpoints: builder => ({
getUser: builder.query({
query: id => /${id}
,
providesTags: ['Users'],
}),
signUpUser: builder.mutation({
query: values => ({
url: '/signup',
method: 'POST',
body: values,
}),
invalidatesTags: ['Users'],
}),
signInUser: builder.mutation({
query: values => ({
url: '/signin',
method: 'POST',
body: values,
}),
invalidatesTags: ['Users'],
}),
updateUser: builder.mutation({
query: values => ({
url: '/update',
method: 'PUT',
body: values,
}),
invalidatesTags: ['Users'],
}),
updateAvatar: builder.mutation({
query: formData => ({
url: '/avatar',
method: 'PATCH',
body: formData,
}),
invalidatesTags: ['Users'],
}),
updateLikes: builder.mutation({
query: ({ id, count }) => ({
url: /${id}/counter
,
method: 'PATCH',
body: count,
}),
invalidatesTags: ['Users'],
}),
logOutUser: builder.mutation({
query: () => ({
url: '/logout',
// method: 'DELETE',
method: 'POST',
}),
invalidatesTags: ['Users'],
}),
}),
});
export const { useGetUserQuery, useSignInUserMutation, useSignUpUserMutation, useUpdateUserMutation, useUpdateAvatarMutation, useLogOutUserMutation, useUpdateLikesMutation, } = userApi;
The state contains a complex object. user: { queries: {}, mutations: { xkgQOHNKtIxY2Pi6bzmEd: { requestId: 'xkgQOHNKtIxY2Pi6bzmEd', status: 'fulfilled', endpointName: 'signInUser', startedTimeStamp: 1712830350747, data: { id: '6616dd9035336472865f647b', name: 'Tom', email: 'tom@gmail.com', viewsCount: 0, }, fulfilledTimeStamp: 1712830351548 } },
How to get the User from the state and move it to localStorage ?
Hi folks π,
I just installed the redux-persist in a project still in its early stages and I'm facing this error message in the console as first thing when the page loads. I haven't done much besides including the lib as is, and my reducers are pretty simple for now, so I believe it has something to do with redux-persist itself?
Error:
Code above is followed by this message:
SS of the whole thing:
Could anyone help me pointing me in the right direction? It does not break the application, but the error message is there in the console.
Cheers,