1

I am doing a NextJS project using next-redux-wrapper, redux/toolkit and redux-saga. This is my setup:

store/enquiry/slice.ts:

import { PayloadAction, createSlice } from '@reduxjs/toolkit'
import { HYDRATE } from 'next-redux-wrapper';

export enum LoadingTracker {
  NotStarted,
  Loading,
  Success,
  Failed
}
type EnquiryState = {
  enquiries: Enquiry[],
  loadingTracker: LoadingTracker
}

const initialState: EnquiryState = {
  enquiries: [],
  loadingTracker: LoadingTracker.NotStarted
}

export const enquirySlice = createSlice({
  name: 'enquiries',
  initialState,
  reducers: {
  //@ts-ignore
  loadEnquiries: (state, action: PayloadAction<Enquiry[]>) => {
    state.enquiries = action.payload;
    state.loadingTracker = LoadingTracker.Success
  },
  failedLoadEnquiries: (state) => {
    state.loadingTracker = LoadingTracker.Failed;
  },
  startedLoadingEnquiries: (state) => {
   state.loadingTracker = LoadingTracker.Loading;
  }
},
 extraReducers:{
   [HYDRATE]:(state, action) => {
   return{
     ...state,
     ...action.payload.enquiry
    };
   }
  },
});

export const { loadEnquiries, failedLoadEnquiries, startedLoadingEnquiries } = 
enquirySlice.actions;
export default enquirySlice.reducer;

This is my enquiry saga setup: sagas/enquiry/saga.ts

import { call, put, takeLatest } from "redux-saga/effects";
import { loadEnquiries, startedLoadingEnquiries, failedLoadEnquiries } from 
"../../store/enquiry/slice";

export function* loadEnquiriesSaga() {
   try {
     //@ts-ignore
     let response = yield call(() =>
       fetch("https://xxxxx686888wwg326et2.mockapi.io/enqueries")
      );
     if (response.ok) {
        //@ts-ignore
        let result = yield call(() => response.json());
        yield put(loadEnquiries(result));
     } else {
        yield put(failedLoadEnquiries());
     }
   } catch (e) {
      yield put(failedLoadEnquiries());
   }
 }

 export function* loadEnquiriesWatcher() {
    const { type } = startedLoadingEnquiries();
    yield takeLatest(type, loadEnquiriesSaga);
 }

This is my root saga setup: sagas/index.js

import { all } from 'redux-saga/effects';
import { loadEnquiriesWatcher } from './enquiry/saga';

export default function* rootSaga() {
   yield all([
   loadEnquiriesWatcher()
])
}

this is my store setup: store/index.js

 import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
 import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
 import createSagaMiddleware from "redux-saga";
 import enquiryReducer from '../store/enquiry/slice';
 import { createWrapper } from 'next-redux-wrapper';
 import rootSaga from '../sagas/index'; 
 const makeStore = () => {
   const sagaMiddleware = createSagaMiddleware();
   const store = configureStore({
   reducer: {
     enquiry: enquiryReducer,
   },
   middleware: [...getDefaultMiddleware({ thunk: false }), sagaMiddleware],
   devTools: true
 })
  //@ts-ignore
   store.sagaTask = sagaMiddleware.run(rootSaga);
   return store;
 }
 const store = makeStore();
 export type AppStore = ReturnType<typeof makeStore>;
 export type RootState = ReturnType<typeof store.getState>
 export type AppDispatch = typeof store.dispatch
 export const useAppDispatch: () => AppDispatch = useDispatch

This is _app.ts file

import React, { useEffect } from "react";
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import { QueryClient, QueryClientProvider } from "react-query";
import { ReactQueryDevtools } from "react-query/devtools";
import { Provider } from 'react-redux'
import { wrapper } from '../store/index';
const App = ({ Component, ...rest }: AppProps) => {
  const [queryClient] = React.useState(() => new QueryClient());
  const { store, props } = wrapper.useWrappedStore(rest);
  const { pageProps } = props;
  return (
    <Provider store={store}>
      <QueryClientProvider client={queryClient}>
        <Component {...pageProps} />
        <ReactQueryDevtools initialIsOpen={false} />
      </QueryClientProvider>
    </Provider>
  );
 }
 export default App;

I am running a getServersideProps function in pages/index.js file.

import Head from 'next/head'
import { Inter } from '@next/font/google'
import utilStyles from '../styles/Utils.module.css';
import Layout from '../components/layout';
import { wrapper } from '../store';
import { startUserLogin } from '../store/user/slice';
import { END } from 'redux-saga';
import { GetServerSideProps } from 'next';
import { startedLoadingEnquiries } from '../store/enquiry/slice';

const inter = Inter({ subsets: ['latin'] })

export const getServerSideProps: GetServerSideProps = wrapper.getServerSideProps(
  //@ts-ignore
  (store) => async ({ req }) => {
  await store.dispatch(startedLoadingEnquiries());
  store.dispatch(END);
  await (store as any).sagaTask.toPromise();
  return {
    props:{
      status:1
    }
  }
})



export default function Home(props:any) {
   return (
     <Layout home>
       <Head>
         <title>Holiday Experts</title>
       </Head>
       <section className={utilStyles.headingMd}>
         <p>Introduction to Holiday Exers blah blah blah............. status: 
          {props.status}</p>
       </section>
      <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}>
         <h2 className={utilStyles.headingLg}>To Do: List of Top Destinatons as 
         cards</h2>
       </section>
    </Layout>
   )
 }

When I got to the home page localhost:3000/, I see all the state values are populated. I go to localhost:3000/enquiries and i see a list of enquiries as well, but when I refresh, the list is empty because, client side state is not set. If I open Redux dev tools, I see enquiry state to be empty all the time.

I think there is something missing during the Hydration of the state. Not sure what it is.Can somebody help me with it?

Here are my references that I followed:

https://romandatsiuk.com/en/blog/post-next-redux-saga/

https://github.com/kirill-konshin/next-redux-wrapper

kumuda
  • 499
  • 2
  • 8
  • 21

0 Answers0