reactjsreduxredux-persist

How to persist only a subset of redux store into the local storage in redux-persist


I have a two reducers - userSignup and userLogin. I have to persist the store between page refreshes so i am using redux persist. However, i don't want to store the entire userSignup and userLogin states into localStorage, i only want to storea part of them.

UserSignupReducer.js

import {
  USER_SIGNUP_SUCCESS,
  USER_SIGNUP_FAILED,
  USER_OTP_VERIFICATION_FAILED,
  USER_OTP_VERIFICATION_SUCCESS,
  SET_LOADING_TRUE,
  SET_LOADING_FALSE,
} from './UserSignupTypes';

const initialState = {
  loading: false,
  userData: {},
  signupErrors: {},
  signupSuccess: false,
  OTPSuccess: false,
  OTPErrors: '',
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case SET_LOADING_TRUE:
      return {
        ...state,
        loading: true,
      };
    case SET_LOADING_FALSE:
      return {
        ...state,
        loading: false,
      };
    case USER_SIGNUP_SUCCESS:
      return {
        ...state,
        signupSuccess: true,
        signupErrors: {},
        userData: action.payload,
        OTPErrors: '',
      };
    case USER_SIGNUP_FAILED:
      return {
        ...state,
        signupSuccess: false,
        signupErrors: action.payload,
      };
    case USER_OTP_VERIFICATION_SUCCESS:
      return {
        ...state,
        OTPSuccess: true,
        OTPErrors: '',
      };
    case USER_OTP_VERIFICATION_FAILED:
      return {
        ...state,
        OTPErrors: action.payload,
      };
    default:
      return state;
  }
};

export default reducer;

Here the state has many variables. But i don't want to persist errors, loading,.. into localStorage (as the UX would not be good if user sees the error even after refreshing the page). I only want to persist userData into the localStorage. Then i can use state reconciler = automergeLevel1 as stated in redux persist docs to get the new state after persist.

Similarly in userLoginReducer.js

import {
  SET_LOADING_TRUE,
  SET_LOADING_FALSE,
  USER_LOGIN_SUCCESS,
  USER_LOGIN_FAILED,
} from './UserLoginTypes';

const initialState = {
  loading: false,
  isloggedIn: false,
  loginErrors: {},
  username: '',
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case SET_LOADING_TRUE:
      return {
        ...state,
        loading: true,
      };
    case SET_LOADING_FALSE:
      return {
        ...state,
        loading: false,
      };
    case USER_LOGIN_SUCCESS:
      return {
        ...state,
        isLoggedIn: true,
        username: action.payload,
        loginErrors: {},
      };
    case USER_LOGIN_FAILED:
      return {
        ...state,
        isLoggedIn: false,
        loginErrors: action.payload,
      };
    default:
      return state;
  }
};

export default reducer;

I only want to persist isLoggedIn into the localStorage.

rootReducer.js

import { combineReducers } from 'redux';
import userSignupReducer from './UserSignup/UserSignupReducer';
import userLoginReducer from './UserLogin/UserLoginReducer';
import { persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';

const rootReducer = combineReducers({
  userSignup: userSignupReducer,
  userLogin: userLoginReducer,
});

const persistConfig = {
  key: 'root',
  storage,
  whitelist: ['userSignup', 'userLogin'],
};

export default persistReducer(persistConfig, rootReducer);

store.js

import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import rootReducer from './rootReducer';
import { composeWithDevTools } from 'redux-devtools-extension';
import { persistStore } from 'redux-persist';
import thunk from 'redux-thunk';

export const store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(logger, thunk)),
);

export const persistor = persistStore(store);

Please suggest any remedy for this problem. Thanks iin advance.


Solution

  • Use the filter transformator for redux-persist module redux-persist-transform-filter.

    Installation:

    npm install redux-persist-transform-filter

    In your rootReducer.js:

    ...
    import { createFilter } from "redux-persist-transform-filter";
    
    ...
    
    const saveUserLoginSubsetFilter = createFilter("userLogin", ["isLoggedIn"]);
    
    const persistConfig = {
      key: 'root',
      storage,
      whitelist: ['userSignup', 'userLogin'],
      transforms: [saveUserLoginSubsetFilter]
    };
    
    export default persistReducer(persistConfig, rootReducer);
    

    The constant saveUserLoginSubsetFilter you are creating is taking two parameters, the first one is the name of the reducer you are referencing, the second one is the array of fields you want to persist. Indeed creating a subset of whitelisted entities to persist.

    Then add the transforms array to the persistConfig and it should work.