Search code examples
javascriptreactjsreduxredux-toolkitredux-persist

accessing redux store from inside a function caused non persisted state RTK


My persisted state was working correctly but after accessing store from a function to do some tests with preloaded state parameter it can't be persisted. It's rehydrated at first render but nothing accessed or persisted to the browser. I think when state is updated nothing causes rerender from the store, but how to solve it?

store

export default function setupStore (preloadedState?: PreloadedState<RootState>) {
  const store = configureStore({
    reducer: persistedReducer,
    preloadedState,
    devTools: process.env.NODE_ENV !== 'production',
    middleware: getDefaultMiddleware => 
      getDefaultMiddleware({
        serializableCheck:  {
          ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
        }
      }).concat(logger),
  })
  return store
}

export const persistor = persistStore(setupStore())

//root reducer

export const rootPersistConfig = {
  key: 'root',
  storage: storage,
  whitelist: ['dealerStoreReducer'],//soon later,
  stateReconciler: autoMergeLevel2 ,
  // version: 1,
}
  
export const dealerStorePersistConfig = {
  key: 'dealerStore',
  storage: storage,
  whitelist: ['cartItems','adminStore'],
  // version: 1,
  //blacklist: ['dealerStoreReducer'],//soon later,
  stateReconciler: autoMergeLevel2 ,
}

export type DealerStoreReducer = initialStatedealerStore & PersistPartial;

const rootReducer = combineReducers({
  labels: labelsReducer,
  dealers: dealersReducer,
  user: usersReducer,
  orders: ordersReducer,
  orderItems: orderItemsReducer,
  dealerStore: persistReducer<initialStatedealerStore, any>(dealerStorePersistConfig, dealerStoreReducer),
})

export type RootReducer = ReturnType<typeof rootReducer>;
export const persistedReducer = persistReducer<RootReducer >(rootPersistConfig, rootReducer) 

export default rootReducer

index

root.render(
  <Provider store={setupStore()}>
    <BarsContextProvider>
      <PersistGate loading={null} persistor={persistor}>
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </PersistGate>
    </BarsContextProvider>,
  </Provider>,
);

Solution

  • It's not clear what exactly you are doing with any specific store instance, but according to the code you've shown you've instantiated at least two different store objects. One when creating the persistor and the other when passing a store to the react-redux Provider component.

    store.js

    export default function setupStore (preloadedState?: PreloadedState<RootState>) {
      const store = configureStore({
        reducer: persistedReducer,
        preloadedState,
        devTools: process.env.NODE_ENV !== 'production',
        middleware: getDefaultMiddleware => 
          getDefaultMiddleware({
            serializableCheck:  {
              ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
            }
          }).concat(logger),
      });
      return store;
    }
    
    export const persistor = persistStore(setupStore()); // <-- store instance #1
    

    index.js

    root.render(
      <Provider store={setupStore()}> // <-- store instance #2
        <BarsContextProvider>
          <PersistGate loading={null} persistor={persistor}>
            <BrowserRouter>
              <App />
            </BrowserRouter>
          </PersistGate>
        </BarsContextProvider>,
      </Provider>,
    );
    

    To resolve you'll want to instantiate only a single store instance to be used across the app.

    You can either export the setupStore function for use in testing/etc, and then also an instantiated store and persistor:

    store.js

    export default function setupStore (preloadedState?: PreloadedState<RootState>) {
      const store = configureStore({
        reducer: persistedReducer,
        preloadedState,
        devTools: process.env.NODE_ENV !== 'production',
        middleware: getDefaultMiddleware => 
          getDefaultMiddleware({
            serializableCheck:  {
              ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
            }
          }).concat(logger),
      });
      return store;
    }
    
    export const store = setupStore(); // <-- store instance
    
    export const persistor = persistStore(store); // <-- store instance passed in
    

    index.js

    root.render(
      <Provider store={store}> // <-- same store instance
        <BarsContextProvider>
          <PersistGate loading={null} persistor={persistor}> // <-- also used here
            <BrowserRouter>
              <App />
            </BrowserRouter>
          </PersistGate>
        </BarsContextProvider>,
      </Provider>,
    );
    

    Or you can just export the setupStore utility and instantiate the store and persistor in the index.js file.

    store.js

    export default function setupStore (preloadedState?: PreloadedState<RootState>) {
      const store = configureStore({
        reducer: persistedReducer,
        preloadedState,
        devTools: process.env.NODE_ENV !== 'production',
        middleware: getDefaultMiddleware => 
          getDefaultMiddleware({
            serializableCheck:  {
              ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
            }
          }).concat(logger),
      });
      return store;
    }
    

    index.js

    const store = setupStore(); // <-- instantiate store
    const persistor = persistStore(store); // <-- pass store instance
    
    root.render(
      <Provider store={store}> // <-- same store instance
        <BarsContextProvider>
          <PersistGate loading={null} persistor={persistor}> // <-- also used here
            <BrowserRouter>
              <App />
            </BrowserRouter>
          </PersistGate>
        </BarsContextProvider>,
      </Provider>,
    );