The storage does not reflect updates when using redux-persist with next-redux-wrapper in a Typescript project

I'm currently working on integrating redux-persist with next.js using next-redux-wrapper. However, I'm facing an issue where the storage is not updating and the state is lost during page refresh.

Below is my store.ts file:

import { createStore, applyMiddleware } from 'redux';
import { createWrapper } from 'next-redux-wrapper';
import storage from 'redux-persist/lib/storage';
import rootReducer from './rootReducer';
import { createLogger } from 'redux-logger'
import { persistStore, persistReducer } from 'redux-persist';
import { composeWithDevTools } from 'redux-devtools-extension';


const logger = createLogger();


// MIDDLEWARE BINDING
const bindMiddleware = (middleware) => {
    if (process.env.NODE_ENV !== 'production') {

        return composeWithDevTools(applyMiddleware(...middleware));
    }
    return applyMiddleware(...middleware);
};

const makeStore: any = ({ isServer }) => {
    if (isServer) {
        //If it's on the server side, create a store
        return createStore(rootReducer, bindMiddleware([logger]));
    } else {
        //If it's on the client side, create a store that will persist


        const persistConfig = {
            key: 'root',
            storage,
        };

        const persistedReducer = persistReducer(persistConfig, rootReducer);

        const store: any = createStore(
            persistedReducer,
            bindMiddleware([logger])
        );



        store.__persistor = persistStore(store);
        return store;
    }
};


export const wrapper = createWrapper(makeStore);

Here is my reducer.ts file:

import {
    LOGOUT,
    LOGIN_ERROR,
    LOGIN_SUCCESS,
} from "./actionTypes";


const initialState = {
    userInfo: null,
    accessToken: null,
    loginError: false,
    loading: true,
    isLoggedIn: false
};



const authReducer = (state: any = initialState, action: any) => {

    switch (action.type) {

        case LOGIN_SUCCESS:
            state = {
                ...state,
                userInfo: action.payload.userInfo,
                accessToken: action.payload.accessToken,
                loading: false,
                isLoggedIn: true
            }
            break;
        case LOGIN_ERROR:

            state = {
                ...state
            }
            break;
        case LOGOUT:

            state = {
                ...state,
                userInfo: null,
                accessToken: null,
                loginError: false,
                loading: false,
                isLoggedIn: false
            }

            console.log(state);
            break;
        default:
            state = {
                ...state,
            };
            break;
    }


    return state;
};

export default authReducer;

And here is my _app.tsx file:

import type { AppProps } from "next/app";
import "../styles/reset.scss";
import Layout from "@/components/layout";
import { wrapper } from "../src/redux/store"
import { useStore } from "react-redux"
import { PersistGate } from "redux-persist/integration/react";
import { ApolloProvider } from "@apollo/client";
import { useApollo } from "../src/graphql/apollo/apollo";
import Loader from '@/components/Loader'



function MyApp({ Component, pageProps }: AppProps) {
  const apolloClient = useApollo(pageProps.initialApolloState);
  const store: any = useStore();
  return (
    <ApolloProvider client={apolloClient}>
      <PersistGate persistor={store.__persistor} loading={<div>Loading</div>}>
        <Layout>
          <Loader />
          <Component {...pageProps} />
        </Layout>
      </PersistGate>
    </ApolloProvider>
  );
}

export default wrapper.withRedux(MyApp);

Do you think there's a need to handle the persist/REHYDRATE action in the reducer file? I've noticed that when checking the persist/REHYDRATE action, the payload is undefined. What could be causing this?

Answer №1

After much searching, I finally cracked it! Below is my store.ts file:

import { createStore, applyMiddleware } from 'redux';
import { createWrapper } from 'next-redux-wrapper';
import storage from 'redux-persist/lib/storage';
import rootReducer from './rootReducer';
import rootSaga from './rootSaga'
import { createLogger } from 'redux-logger'
import { persistStore, persistReducer } from 'redux-persist';
import { composeWithDevTools } from 'redux-devtools-extension';
import createSagaMiddleware from "redux-saga";

const logger = createLogger();
const sagaMiddleware = createSagaMiddleware();

// MIDDLEWARE BINDING
const bindMiddleware = (middleware) => {
    if (process.env.NODE_ENV !== 'production') {
        return composeWithDevTools(applyMiddleware(...middleware));
    }
    return applyMiddleware(...middleware);
};

const makeStore: any = ({ isServer }) => {
    if (isServer) {
        // Server-side store creation
        return createStore(rootReducer, bindMiddleware([logger]));
    } else {
        // Client-side store creation with persistence

        const persistConfig = {
            key: 'root',
            storage,
        };

        const persistedReducer = persistReducer(persistConfig, rootReducer);

        const store: any = createStore(
            persistedReducer,
            bindMiddleware([logger, sagaMiddleware])
        );
        store.__persistor = persistStore(store);
        sagaMiddleware.run(rootSaga);
        return store;
    }
};

export const wrapper = createWrapper(makeStore);

And here is my _app.tsx file:

import type { AppProps } from "next/app";
import "../styles/reset.scss";
import Layout from "@/components/layout";
import { wrapper } from "@/redux/store";
import { useStore } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { ApolloProvider } from "@apollo/client";
import { useApollo } from "@/graphql/apollo/apollo";
import Head from "next/head";
import SimpleReactLightbox from "simple-react-lightbox";

function MyApp({ Component, pageProps }: AppProps) {
  const apolloClient = useApollo(pageProps.initialApolloState);
  const store: any = useStore();

  return (
   
    <ApolloProvider client={apolloClient}>
      <PersistGate persistor={store.__persistor} loading={null}>
        <SimpleReactLightbox>
          <Layout>
           
            <Head>
              <meta
                name="viewport"
                content="width=device-width, initial-scale=1.0, maximum-scale=1.0"
              />
            </Head>
            <Component {...pageProps} />
          </Layout>
        </SimpleReactLightbox>
      </PersistGate>
    </ApolloProvider>
  
  );
}

export default wrapper.withRedux(MyApp);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error encountered with default theme styling in Material-UI React TypeScript components

Currently, I am working on integrating Material-UI (v4.4.3) with a React (v16.9.2) TypeScript (v3.6.3) website. Following the example of the AppBar component from https://material-ui.com/components/app-bar/ and the TypeScript Guide https://material-ui.com/ ...

The result of comparing with `instanceof` in TypeScript

class Department { name: string; constructor(n: string) { this.name = n; } describe(this: Department){ console.log('department: ' +this.name); } } const frontend = new Department('frontend'); frontend.describe(); con ...

Adding extra fields to an existing JSON response in a TypeScript REST API

I am in need of an additional column to be added to my response data. Currently, I am fetching data from multiple REST endpoints one by one and merging the results into a single JSON format to display them in an Angular Mat table. The columns that I want t ...

Can the child component ensure that the Context value is not null?

In the process of developing a Next.js/React application with TypeScript, I've implemented a UserContext in pages/_app.js that supplies a user: User | null object to all child components. Additionally, there's a ProtectedRoute component designed ...

The FOR UPDATE clause is not functioning as intended in the SELECT query

I have been working on isolating my database to prevent multiple servers from reading or updating data in the same row. In order to achieve this, I have structured my query like so: SELECT * FROM bridge_transaction_state as bridge WHERE bridge.state IN (&a ...

What steps should I take to resolve the NextRouter "not mounted" error when deploying my Next JS 13 app on Vercel

I am encountering an issue while deploying my Next.js 13 app. The error message states: Module not found: Can't resolve 'encoding' in '/vercel/path0/node_modules/node-fetch/lib' Additionally, I am facing a "Next Router not mounte ...

The custom layout in NestJS version 13 failed to display

I have implemented NextJs 13 in my project for building purposes. I am trying to use CustomLayout as the primary layout for my entire website. Even though there are no errors, I am facing an issue where the CustomLayout does not display as expected. ...

Is there a way to retrieve the initial item of a JSON array from an HTML document using Angular 2?

Within the src/assets/ directory, I have a json file called product.json with the following structure: [ { "images": "http://openclipart.org/image/300px/svg_to_png/26215/Anonymous_Leaf_Rake.png", "textBox": "empty", "comments": "empty" }, { "i ...

Having issues with importing images in Next.js using the Next Images package

Having trouble with importing images locally from the images folder. Error message: "Module not found: Can't resolve '../images/banner1.jpg'" https://i.stack.imgur.com/Dv90J.png Attempting to access images in ImagesSlider.js file at compo ...

Guide to invoking an API in Next.js 13 by utilizing specific variables within a client component

I currently have a collection of products that are accessible on my website through a straightforward function within a server component. async function getData() { const res = await fetch(`${apiPath}`); const data = (await res.json()) as PackProps ...

AWS Amplify is not displaying images correctly, although they are functioning properly in development mode

I am facing an issue with my Next.js project deployed on AWS Amplify. While images load properly in development mode, they are not loading in production mode. I have tried various solutions such as: Enabling the "Legacy cache settings" option and setting ...

Jest's --findRelatedTests fails to identify associated test cases

Whenever I execute the command jest --bail --findRelatedTests src/components/BannerSet/BannerSet.tsx , an unexpected message is displayed: I couldn't locate any tests and hence exiting with code 1 If you want to exit with code 0 even when there are n ...

After resolving a promise, what is the process for loading a Next.js App?

Seeking guidance on implementing the code snippet below using Next.js. I suspect there is an issue with Next.js not being able to access the window object without being within a useEffect(() => {}) hook. When switching back to regular React, the code ...

What is the method for generating an observable that includes a time delay?

Question In order to conduct testing, I am developing Observable objects that simulate the observable typically returned by an actual http call using Http. This is how my observable is set up: dummyObservable = Observable.create(obs => { obs.next([ ...

What type of value does a `use` directive return?

Upon reviewing the svelte tutorial, I observed that the clickOutside function provides an object with a destroy method. What should be the precise return type of a custom use directive? export function clickOutside(node: HTMLElement): ??? { // Initia ...

Unable to fix stripe - importing axios using axios in NEXTJS

I encountered an issue while attempting to create a checkout session, as I received an error message pointing to a specific line in the log. Despite having both components installed and included in my package.json file, I'm unsure why this discrepancy ...

Is it possible to implement custom classes in @apply within a SCSS file in a Tailwind Next.js project?

Having trouble implementing a custom class overflow:inherit as @apply overflow-inherit in my next.js project with tailwind. It seems to be causing an error. Strangely, I can successfully use pre-built tailwind classes like @apply flex flex-col md:h-full h- ...

Managing multiple asynchronous requests through Observables in web development

I am working on an Angular2 website that sends multiple ajax requests using Json Web Tokens for authorization when it is initialized Here are two examples: public getUser(): Observable<User> { // Code block to get user data } public getFriends ...

The React DOM isn't updating even after the array property state has changed

This particular issue may be a common one for most, but I have exhausted all my options and that's why I am seeking help here. Within my React application, I have a functional component named App. The App component begins as follows: function App() ...

Expanding User Type to Include Extra User Data Using NextAuth.js

I encountered a dilemma where I needed to include the "profile" property in my section object to cater to different user personas in my application. However, despite retrieving the logged-in user's data from the backend and storing it in the NextAuth. ...