rt2zz / redux-persist

persist and rehydrate a redux store
MIT License
12.91k stars 863 forks source link

Encountering "TypeError: action.rehydrate is not a function" while using Redux Toolkit and redux-persist #1344

Closed joekrall closed 2 years ago

joekrall commented 2 years ago

I am using redux-persist with Redux Toolkit, and have followed the docs' advice to ignore the types redux-persist dispatches.

I am attempting to save a username in sessionStorage after logging into my application. When I refresh the tab, I receive the following error in Redux Devtools: "redux-persist: either rehydrate or register is not a function on the PERSIST action. This can happen if the action is being replayed. This is an unexplored use case, please open an issue and we will figure out a resolution."

Following this, I receive a TypeError thrown from _rehydrate in persistReducer: "TypeError: action.rehydrate is not a function."

  58 |   if (process.env.NODE_ENV !== 'production' && _sealed) console.error("redux-persist: rehydrate for \"".concat(config.key, "\" called after timeout."), payload, err); // only rehydrate if we are not already sealed
  59 | 
  60 |   if (!_sealed) {
> 61 |     action.rehydrate(config.key, payload, err);
     | ^  62 |     _sealed = true;
  63 |   }
  64 | };

This error seems to be related to the default Serializability Middleware that Redux Toolkit adds. When I do not use their default middleware and use my own array (including everything except a serializability checker), I do not receive the TypeError.

I am aware that redux-persist is undergoing some changes (most recently moving to TypeScript).

Here is my store setup. I am using the setupStore function in my testing utils, but export the store by default.

src/Redux/store.tsx

import { configureStore, PreloadedState } from '@reduxjs/toolkit';
import {  
  persistReducer, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER,
} from 'redux-persist';
import storageSession from 'redux-persist/lib/storage/session';
import { api } from './api';
import rootReducer from './reducers';

// Using redux-persist to save state to sessionStorage
const persistConfig = {
  key: 'root',// <-- yes, this API is correct
  storage: storageSession,
  whitelist: ['login'], // ONLY login will be persisted
};

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const setupStore = (preloadedState?: PreloadedState<RootState>) => {
  return configureStore({
    reducer: persistReducer(persistConfig, rootReducer),
    middleware: (getDefaultMiddleware) => getDefaultMiddleware({ 
      serializableCheck: {
      // Ignore all the action types redux-persist dispatches:
      // https://redux-toolkit.js.org/usage/usage-guide#use-with-redux-persist
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
      // This enables caching, invalidation, polling, and other features of RTK Query
    }).concat(api.middleware),
    preloadedState,
  });
};

const store = setupStore();

export default store;

export type RootState = ReturnType<typeof rootReducer>;
export type AppStore = ReturnType<typeof setupStore>;
export type AppDispatch = AppStore['dispatch'];

Here is the index.tsx file:


import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
import { PersistGate } from 'redux-persist/integration/react';
import reportWebVitals from './reportWebVitals';
import App from './App';
import store from './Redux/store';
import 'leaflet-draw/dist/leaflet.draw.css';
import './App.scss';

const persistor = persistStore(store);

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </PersistGate>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root'),
);
joekrall commented 2 years ago

I am unable to reduplicate the message I received today today. Closing this issue - my apologies, and thank you for the work you do!