redux-resist losing data on refresh - reactjs

My App Component
My Store
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage'; // defaults to localStorage for web
import { rootReducer } from './reducers';
const persistConfig = {
key: 'root',
storage,
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
let store = createStore(persistedReducer);
let persistor = persistStore(store);
export { store, persistor };
localStorage
After refresh / reload the cartItems become empty
package info
react: "^17.0.2",
react-redux: "^7.2.3",
redux-persist: "^6.0.0",
I can see data being store on localStorage but on page refresh, i am losing the data

Add whitelist to your persistConfig variable by passing "auth" only auth reducers will be persisted. you can define as many as reducers in the whitelist you want to be persisted. This should resolve your issue.
const persistConfig = {
key: 'root',
storage,
whitelist: ["auth"] //
};
Go through this npm Readme for more clarification: https://www.npmjs.com/package/redux-persist#blacklist--whitelist

Related

redux-persist whitelist not working with rtk

I am using the createSlice function from the rtk library to create multiple reducers in my Redux store. I am also trying to use redux-persist to save certain slices to local storage.
this store.js code is working well:
import { combineReducers, configureStore } from "#reduxjs/toolkit";
import betSlice from "./features/betSlice";
import configSlice from "./features/configSlice";
import eventSlice from "./features/eventSlice";
import userDataSlice from "./features/userDataSlice";
import wsSlice from "./features/wsSlice";
import storage from "redux-persist/lib/storage";
import { persistReducer, persistStore } from "redux-persist";
import thunk from "redux-thunk";
import modalsSlice from "./features/modalsSlice";
const persistConfig = {
key: "root",
storage,
};
const presistedReducers = combineReducers({
wsSlice: persistReducer(persistConfig, wsSlice),
eventSlice: persistReducer(persistConfig, eventSlice),
betSlice: persistReducer(persistConfig, betSlice),
configSlice: persistReducer(persistConfig, configSlice),
userDataSlice: persistReducer(persistConfig, userDataSlice),
modalsSlice: persistReducer(persistConfig, modalsSlice),
});
export const store = configureStore({
reducer: presistedReducers,
middleware: [thunk],
});
export const persistor = persistStore(store);
I am having trouble using the whitelist\blacklist options provided by redux-persist. when I try to use a whitelist to only persist the configSlice reducer like this:
const persistConfig = {
key: "root",
storage,
whitelist: ["configSlice"],
};
nothing is saved to local storage.
Similarly, when I try to use a blacklist, all of the reducers are saved to local storage.
All of the slices in my project are structured in the same way, using the createSlice function in this format:
import { createSlice } from '#reduxjs/toolkit';
const initialState = {};
const nameSlice = createSlice({
name: 'nameSlice',
initialState,
reducers: {},
});
export const {} = nameSlice.actions;
export default nameSlice.reducer;
Can anyone explain why the whitelist and blacklist options are not working as expected, and how I can correctly configure redux-persist to only save certain slices to local storage?

redux-presist not updating local storage a browser

I'm using redux-persist for my e-commerce project.
When I updated my app to new version I found a new bug.
I changed my initialState from array into object.
My app in Chrome (browser that i test and run my app on it) crashed !! because my initialState still array(NOT UPDATE) and new method was not returned anything. (Of course).
But in Mozilla and other Browsers that I not use before them my app working currently !
why!?
My Store Config :
import { createStore, applyMiddleware } from 'redux'
import { persistStore } from 'redux-persist'
import logger from 'redux-logger'
import RootReducer from './RootReducer'
const middleware = [logger]
export const store = createStore(RootReducer, applyMiddleware(...middleware))
export const persistore = persistStore(store)
My rootReducer Config :
import { combineReducers } from 'redux'
import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import UserReducer from './User/UserReducer'
import ShoppingBagDropdownReducer from './ShoppingBagDropdown/ShoppingBagDropdownReducer'
import DirectoryReducer from './Directory/DirectoryReducer'
import ShopDataReducer from './ShopData/ShopDataReducer'
const persistConfig = {
key: 'root',
storage,
whileList: ['shoppingBagDropdown']
}
const rootReducer = combineReducers({
user: UserReducer,
shoppingBagDropdown: ShoppingBagDropdownReducer,
shopData: ShopDataReducer,
directory: DirectoryReducer
})
export default persistReducer(persistConfig, rootReducer)
Yeah :)
I found solution and that is : clear local storage with :
localStorage.clear();
I saw that you fixed it, but you could also do it without code using google chrome.
CTRL + SHIFT + I > Application > Local Storage
Now you just have to open the localstorage, right click and click on clear.

How to persist to both localStorage and sessionStorage at the same time using redux-persist?

I'm implementing a login form using react, redux and redux-persist. Login API is ready from back-end team. The form has a "remember me" checkbox and I want to persist JWT auth token from login response.
What I think is the right way to implement "remember me" is this:
If "remember me" is not checked, token should be persisted to
sessionStorage. So that when browser is closed, user should login again but does not need login on switching tab or refreshing current page.
If it is checked, token should be persisted to localStorage. User is still logged in even if the browser is closed.
Now I know from our back-end perspective there is only token expiration time.
My first question is if my client side view and approach is correct or not.
If it is, how can I update my persist config based on login "remember me" checkbox?
My current store.js is this:
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import rootReducer from './reducers';
const persistConfig = {
key: 'root',
storage,
whitelist: ['auth'],
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = createStore(persistedReducer);
const persistor = persistStore(store);
export {
store, persistor
};
And it is used here:
import React from 'react';
import ReactDOM from 'react-dom';
import App from 'js/containers/App';
import { store, persistor } from './store';
const render = Component => {
ReactDOM.render(
<Component store={store} persistor={persistor}/>,
document.getElementById('root')
)
};
render(App);
if (module.hot) {
module.hot.accept('js/containers/App', () => {
const NextApp = require('js/containers/App').default;
render(NextApp);
});
}
I want to change persistConfig based on login form and use sessionStorage instead of localStorage but it's like store structure is formed here and there is no way to change it in app.
Any idea how to implement this?
I don't think you can change storage after creating but you can have 2 sub-tree on different storages. So tick/untick "remember me" will save in different trees and make a function to get the token from both sources.
to create sub-tree on difference storage see this
https://github.com/rt2zz/redux-persist#nested-persists
Edit
Adding sample for clarity.
import { combineReducers } from 'redux'
import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import storageSession from 'redux-persist/lib/storage/session'
const rootPersistConfig = { key: 'root', storage, whitelist: ['cart','user'] };
const authPersistConfig = { key: 'user', storage:storageSession }; // This is to session storage
const rootReducer = combineReducers({
user: persistReducer(authPersistConfig,userReducer), // user subtree saved in session storage
cart: cartReducer,
directory: directoryReducer,
shop: shopReducer });
export default persistReducer(rootPersistConfig, rootReducer);

redux-persist not updating local storage even after successful dispatch

In my app on log out I'm doing this.props.dispatch(setUserSession({})) even passed null here. After dispatching in redux-logger I can see that it's changed to
action {type: "SET_USER_SESSION", userSession: {}}
next state {userSession: {}
But in local storage, I can still see the userSession that was there before dispatching null.
On what action or when will the persisted store will get updated.
I'm setting userSession to null on logout, but when the user refreshes the page, he is back in without login since the token is present in the store.
And also I don't want to do a purge or flush the full store, just that userSession key.
Current store configuration
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import reducer from './reducers';
let middleware = [thunk];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const configureStore = composeEnhancers(applyMiddleware(...middleware))(createStore);
const config = {
key: 'root',
storage
};
const combinedReducer = persistReducer(config, reducer);
const store = configureStore(combinedReducer);
const persistor = persistStore(store);
export { persistor, store };
Kindly provide some help, correct me if I'm missing something.

Correct setup of redux-persist v5 with react boilerplate

I have been trying to setup redux-persist 5.9.1 with reactboilerplate 3.4.0 framework.
The error I receive seems to related to redux-immutable and I am unable to figure out right configuration.
Here is what I have done so far:
1. Install NPM
npm i -S redux-persist redux-persist-transform-immutable
package.json
"redux-persist": "^5.9.1",
"redux-persist-transform-immutable": "^5.0.0",
2. Setup Redux Persist in store.js
//store.js
import .... (other usual stuff)
import { persistStore, persistReducer } from 'redux-persist';
import storageSession from 'redux-persist/lib/storage/session';
import immutableTransform from 'redux-persist-transform-immutable';
const persistConfig = {
transforms: [immutableTransform()],
key: 'root',
storage: storageSession,
}
const rootReducers = createReducer();
// Using persistReducer not persistCombineReducer because the rootReducer is already returned by combinedReducer from redux-immutable.
const persistedReducer = persistReducer (persistConfig, rootReducers)
export default function configureStore (initialState = {}, history) {
// other usual stuffs ...
// I modified how store is created using persistedReducer
const store = createStore(
persistedReducer, // this line used to use createReducer() method
fromJS(initialState),
composeEnhancers(...enhancers),
);
const persistor = persistStore(store);
return { persistor, store };
// Please note, I have commented out hot reloading of reducers for now.
}
3. No change in reducers.js
4. Update App.js
import 'babel-polyfill';
import React from 'react';
// Added below
import { PersistGate } from 'redux-persist/es/integration/react';
// other usual setup
// Line below used to define just store but now we are defining persistor and store
const { persistor, store } = configureStore(initialState, browserHistory);
// Finally, update the render method:
const render = () => {
ReactDOM.render(
<Provider store={store}>
<PersistGate persistor={persistor}>
<Router
history={history}
routes={rootRoute}
render={
applyRouterMiddleware(useScroll())
}
/>
</PersistGate>
</Provider>,
document.getElementById('app')
);
};
And still no luck:
Error:
I think I do not have immutable maps configured right. Any help?
The way you doing is correct as documentation.
The problem is in here:
const rootReducers = createReducer();
// Using persistReducer not persistCombineReducer because the rootReducer is already returned by combinedReducer from redux-immutable.
const persistedReducer = persistReducer (persistConfig, rootReducers)
This const rootReducers = createReducer(); should not call like that, it will trigger the function. You should put like const rootReducers = createReducer; or better call like this:
const persistedReducer = persistReducer (persistConfig, createReducer)
Please see documentation, not call rootReducer for trigger function but pass it as variable.

Resources