'Redux store data being reset upon "getServerSideProps" being called; not persisting

Overview: I have a TypeScript NextJS project that I am using Redux-toolkit with to manage state. My file structure for my Redux store and pages are as follows:

enter image description here

(/store is at the root of my project)

enter image description here

Project layout: I have 2 pages (index.tsx and other.txs), both these pages display a counter variable which I get from my store (const counter = useSelector(selectCounter), then displaying {counter.count} on the pages). I also have an "increase count by 1" button on each page. Pressing them on either page updates my Redux store through state.count++ via one of my reducers.

The Problem: My index.tsx page also has a getServerSideProps function which dispatches an action to increment the counter by 1 (same action as the buttons). This works well upon first loading the website to index.tsx, my counter on-screen defaults to 1 because of the getServerSideProps (initialState: {count: 0}, so incrementing 0 by 1 with getServerSideProps renders it instantly as 1). I also use the next/link (<Link/>) component to navigate between the 2 screens (index.tsx & other.tsx).

I can increment the counter value by n amount on the index.tsx page, <Link/> to the other.tsx page, and have the count value persist, however, when I navigate BACK to the index.tsx page, my getServerSideProps method doesn't work (it only has increment count by 1 in it), instead, my count gets reset back to 1 (like new again). Why does this happen? How can I get my count variable to stay the same between navigating between my 2 screens, and then upon navigating back to index.tsx, my getServerSideProps increments it by 1 as it should instead of resetting it?

My code is below for reference:

index.tsx

import type { NextPage } from 'next'
import { useSelector, useDispatch } from 'react-redux';
import { selectCounter, counterActions } from '../store/slices/counter';
import { wrapper } from "../store" // for getserversideprops
import Link from "next/link";

interface HomeProps {
  test: number
}

const Home: NextPage<HomeProps> = (props) => {
  const counter = useSelector(selectCounter);
  const dispatch = useDispatch()
  return (
    <>
      <h1>home, Counter: {counter.count}</h1>
      <button onClick={() => { dispatch(counterActions.increment()); }}>Increment by 1</button>
      <Link href="/other">
        <a>go to OTHER PAGE</a>
      </Link>
    </>
  );
}

export default Home

export const getServerSideProps = wrapper.getServerSideProps(store => async () => {
  await store.dispatch(counterActions.increment());
  return {
    props: {}
  };
});

other.tsx

import { NextPage } from "next";
import Link from "next/link";
import { useDispatch, useSelector } from "react-redux";
import { counterActions, selectCounter } from "../store/slices/counter";

const Other: NextPage = () => {
    const counter = useSelector(selectCounter);
    const dispatch = useDispatch()
    return (
        <>
            <h1>other page, Counter: {counter.count}</h1>
            <button onClick={() => { dispatch(counterActions.increment()); }}>Increment by 1</button>
            <Link href="/">
                <a>go to HOME</a>
            </Link>
        </>
    );
}

export default Other

index.ts (store)

import { configureStore, ThunkAction } from "@reduxjs/toolkit";
import { createWrapper } from "next-redux-wrapper";
import { Action } from "redux";
import counterReducer from "../store/slices/counter";
// we can import multiple reducers here (like our counterReducer)

const makeStore = () => configureStore({
    reducer: {
        counter: counterReducer,
        // multiple reducers can go here that will be combined
    },
    devTools: true,
});

export type AppStore = ReturnType<typeof makeStore>;
export type AppState = ReturnType<AppStore["getState"]>;
export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, AppState, unknown, Action>;

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

counter.ts

import { createSlice } from "@reduxjs/toolkit";
import { HYDRATE } from "next-redux-wrapper";
import { AppState } from "..";

export const CounterSlice = createSlice({
    name: "counter",
    initialState: {
        count: 0,
    },
    reducers: {
        increment: (state) => {
            state.count++;
        },
        // other actions or ways to mutate the data (count) go here
    },
    extraReducers: {
        [HYDRATE]: (state, action) => {
            if (!action.payload.counter.count) {
                return state;
            }
            state.count = action.payload.counter.count;
        }
    }
});

// export multiple actions here
export const counterActions = CounterSlice.actions;

export const selectCounter = (state: AppState) => state.counter;

export default CounterSlice.reducer;

_app.tsx

import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { wrapper } from "../store"

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

export default wrapper.withRedux(MyApp);

(I've read through the similar Stackoverflow questions, NextJS and Redux docs, and still can't figure this out)



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source