Home > Software design >  redux-persist does not save state from redux-toolkit, next-redux-wrapper is used
redux-persist does not save state from redux-toolkit, next-redux-wrapper is used

Time:01-12

I am creating an application on Next js. I use redux-toolkit and next-redux-wrapper in it, I want to save the contents of my store in localStorage. But I ran into a problem - an object from redux-persist appears in the developer console, but its contents do not change when dispatch calls and store changes.

my store

import {
   persistStore,
   persistReducer,
   FLUSH,
   REHYDRATE,
   PAUSE,
   PERSIST,
   PURGE,
   REGISTER,
} from 'redux-persist'
import storage from 'redux-persist/lib/storage'


const makeStore = () => {
   const isServer = typeof window === 'undefined';

   const rootReduser = combineReducers(
      {
         search: searchDataReduser,
         userData: userDataReduser,
         regions: regionsIdReduser,
         loading: visibleLoadingReduser,
         hotelsRegion: hotelsRegionReduser,
         hotelsId: hotelsIdReduser,
         room: roomBookingReduser,
         webRoom: webRoomBookingReduser,
         bookingRoomData: bookingRoomsUserDataReduser
      }
   )

   if (isServer) {
      const store = configureStore({
         reducer: rootReduser,
         middleware: (getDefaultMiddleware) => getDefaultMiddleware({
            immutableCheck: false,
            serializableCheck: false
         })
      })
      return store

   } else {

      const persistConfig = {
         key: "nextjs",
         storage
      }

      const persistedReducer = persistReducer(persistConfig, rootReduser)

      const store = configureStore({
         reducer: persistedReducer,
         middleware: (getDefaultMiddleware) => getDefaultMiddleware({
            immutableCheck: false,
            serializableCheck: {
               ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
            }
         })
      })

      return store
   }
}

export const store = makeStore()
export const persistor = persistStore(makeStore())
export type RootStore = ReturnType<typeof makeStore>;
export type RootState = ReturnType<RootStore['getState']>;
export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, RootState, unknown, Action>;
export type AppDispatch = typeof store.dispatch

export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

export const wrapper = createWrapper<RootStore>(makeStore);

my app component

function App({ Component, pageProps }: AppProps) {
  const loading = useAppSelector(state => state.loading.loading)
  const dispatch = useDispatch()
  const router = useRouter()

  useEffect(() => {
    router.events.on('routeChangeStart', (url) => {
      dispatch(visibleLoadingFunction(true))
    })

    router.events.on('routeChangeComplete', (url) => {
      dispatch(visibleLoadingFunction(false))
    })
  }, [])

  return (
    <>
      <PersistGate persistor={persistor} loading={<div>Loading...</div>}>
        <Head>
          <link rel="icon" href={'./favicon.svg'} type="image/svg" />
        </Head>
        <div className='wrapper'>
          {loading && <LoadingRouter />}
          <Component {...pageProps} />
        </div>
      </PersistGate>
    </>
  )
}

App.getInitialProps = wrapper.getInitialAppProps(store => async ({ ctx, Component }) => {
  try {
//контент
  } catch (err) {
    //контент
  }

  return {
    pageProps: Component.getInitialProps ? await Component.getInitialProps({ ...ctx, store }) : {}
  }
})


export default wrapper.withRedux(App)

One of the Reduser

const initialState: searchStateType = {
   dataBar:
   {
      location: '',
      date: {
         from: undefined,
         to: undefined
      },
      number: {
         adults: 1,
         child: 0,
         rooms: 1
      }
   }
}

const searchDataSlice = createSlice({
   name: 'search',
   initialState,
   reducers: {
      searchbar: (state, action: PayloadAction<searchStateType>) => {
         state.dataBar = { ...action.payload.dataBar }
      }
   },
   extraReducers: {
      [HYDRATE]: (state, action) => {
         return {
            ...state,
            ...action.payload.search
         }
      }
   }
})

export const { searchbar } = searchDataSlice.actions
export default searchDataSlice.reducer

CodePudding user response:

As per the documentation, call persistStore within makeStore:

const makeStore = () => {
  const isServer = typeof window === "undefined";

  const rootReduser = combineReducers({
    search: searchDataReduser,
    userData: userDataReduser,
    regions: regionsIdReduser,
    loading: visibleLoadingReduser,
    hotelsRegion: hotelsRegionReduser,
    hotelsId: hotelsIdReduser,
    room: roomBookingReduser,
    webRoom: webRoomBookingReduser,
    bookingRoomData: bookingRoomsUserDataReduser,
  });

  if (isServer) {
    const store = configureStore({
      reducer: rootReduser,
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
          immutableCheck: false,
          serializableCheck: false,
        }),
    });
    return store;
  } else {
    const persistConfig = {
      key: "nextjs",
      storage,
    };

    const persistedReducer = persistReducer(persistConfig, rootReduser);

    const store = configureStore({
      reducer: persistedReducer,
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
          immutableCheck: false,
          serializableCheck: {
            ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
          },
        }),
    });

    store.__persistor = persistStore(store); // Nasty hack

    return store;
  }
};

and then remove those top-level lines:

export const store = makeStore();
export const persistor = persistStore(makeStore());

and in your App component, get the persistor from the store:

<ReactReduxContext.Consumer>
  {({ store }) => (
    <PersistGate persistor={store.__persistor} loading={<div>Loading</div>}>
      <Head>
        <link rel="icon" href={"./favicon.svg"} type="image/svg" />
      </Head>
      <div className="wrapper">
        {loading && <LoadingRouter />}
        <Component {...pageProps} />
      </div>
    </PersistGate>
  )}
</ReactReduxContext.Consumer>
  • Related