rt2zz / redux-persist

persist and rehydrate a redux store
MIT License
12.94k stars 866 forks source link

Redux persist is not working when redux dev tool is disabled. #1287

Open priosshrsth opened 3 years ago

priosshrsth commented 3 years ago

In my app, redux persist was not working in production. But, everything was working fine on development environment. Turns out it only works when redux dev tool is enabled, which was disabled in production mode. Is it supposed to be like this? I am using these packages in my next.js app:

"@reduxjs/toolkit": "^1.5.0",
"react-redux": "^7.2.2",
"redux-persist": "^6.0.0",
"next": "10.0.3",

Here is my code:

import { combineReducers, configureStore, ThunkAction, Action } from '@reduxjs/toolkit';
import reducerRegistry from 'redux/reduxRegistry';
import { useDispatch } from 'react-redux';
import login from 'features/login/login.slice';
import notification from 'features/notification/notification.slice';
import { FLUSH, PAUSE, PERSIST, persistReducer, persistStore, PURGE, REGISTER, REHYDRATE } from 'redux-persist';
import createWebStorage from 'redux-persist/lib/storage/createWebStorage';

const createNoopStorage = () => {
  return {
    getItem(_key) {
      return Promise.resolve(null);
    },
    setItem(_key, value) {
      return Promise.resolve(value);
    },
    removeItem(_key) {
      return Promise.resolve();
    },
  };
};

const storage = typeof window !== 'undefined' ? createWebStorage('local') : createNoopStorage();

const isProduction = process.env.NODE_ENV === 'production';

const combine = (asyncReducers = {}) => {
  return combineReducers({
    auth: login,
    notification,
    ...asyncReducers,
  });
};

const persistConfig = {
  key: 'root',
  storage,
  whitelist: ['auth', 'register'],
};

const persistedReducer = persistReducer(persistConfig, combine());

const getMiddlewares = (getDefaultMiddleware) => {
  const defaultMiddlewares = getDefaultMiddleware({
    serializableCheck: {
      ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
    },
  });
  if (isProduction) {
    return defaultMiddlewares;
    // eslint-disable-next-line @typescript-eslint/no-var-requires,global-require
    // const { logger } = require('./_fake/logger');
    // return defaultMiddlewares.concat(logger);
  }
  // eslint-disable-next-line @typescript-eslint/no-var-requires,global-require
  const { logger } = require('redux-logger');
  return defaultMiddlewares.concat(logger);
};

export const store = configureStore({
  reducer: persistedReducer,
  middleware: getMiddlewares,
  devTools: false, // It works fine if I set this to true
});

reducerRegistry.setChangeListener((reducers) => {
  store.replaceReducer(persistReducer(persistConfig, combine(reducers)));
});

export const persistor = persistStore(store);

export type RootState = ReturnType<typeof store.getState>;
// @ts-ignore
export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, RootState, unknown, Action<string>>;

export type AppDispatch = typeof store.dispatch;
export const useAppDispatch = () => useDispatch<AppDispatch>();

export const dispatcher = store.dispatch as ReturnType<typeof useAppDispatch>;
mutoo commented 3 years ago

Yeah, I found this issue too.

After review, I realized that I am using redux-injectors to combine the reducers dynamically. Thus I have to set the option: manualPersist: true and manually dispatch the persist event later.

smac89 commented 2 years ago

@mutoo do you call persistor.persist or do you use store.dispatch to call the persist method? Please share your solution for this

mutoo commented 2 years ago

@mutoo do you call persistor.persist or do you use store.dispatch to call the persist method? Please share your solution for this

hi @smac89 here is the code related to my issue

the persistor with manualPersist disabled: https://github.com/mutoo/critterpedia-plus/blob/d0be98768a6bc87ff01e006cceaa57092c9730ab/app/configureStore.js#L65

export const persistor = persistStore(store, { manualPersist: false });

the component that injects persistReducer and manually dispatches persist with persistor: https://github.com/mutoo/critterpedia-plus/blob/d0be98768a6bc87ff01e006cceaa57092c9730ab/app/pages/Critterpedia/index.js#L46

  useInjectReducer({ key, reducer });
  useEffect(() => {
    persistor.persist();
  }, []);

I hope this will help you.

natoszme commented 1 year ago

Hi there! Same issue here. Any solutions? Not using redux-injectors