0

I got Next.js application with Typescript and I'm trying to make redux work with redux-persist, if the state in slice is same as the initial state, the application works fine, but if it actually have to persist some state I get an hydration errors:

  • Hydration failed because the initial UI does not match what was rendered on the server.
  • An error occurred during hydration. The server HTML was replaced with client content in <#document>.
  • Hydration failed because the initial UI does not match what was rendered on the server.

Also getting this error on server: Error storing data ReferenceError: window is not defined

Even though the application works as intended even when there are these errors occuring I would like to solve them, so it doesn't look this messy, but I'm pretty lost on why this is happening.

Here is my trimmed code for redux set up:

slice.ts

import { InquiryCartState } from "@/types/InquiryCart";
import { createSlice } from "@reduxjs/toolkit";

const initialState: InquiryCartState = {
  products: []
};

const inquiryCartSlice = createSlice({
  name: "inquiryCart",
  initialState,
  reducers: {
  },
});

export default inquiryCartSlice.reducer;

rootReducer.ts

import { combineReducers } from "@reduxjs/toolkit";
import inquiryCartReducer from "./slice";
import AsyncStorage from '@react-native-async-storage/async-storage';
import { persistReducer } from "redux-persist";

const persistConfig = {
  key: "root",
  storage: AsyncStorage,
};

export const rootReducer = combineReducers({
  inquiryCart: persistReducer(persistConfig, inquiryCartReducer),
})

store.ts

import { configureStore } from "@reduxjs/toolkit";
import { rootReducer } from "./rootReducer";

export const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({ serializableCheck: false })
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

ReduxProvider.ts

"use client"

import { Provider } from "react-redux";
import { ReactNode } from "react";
import { store } from "@/lib/store";
import { persistStore } from "redux-persist";

persistStore(store)
export default function ReduxProvider({ children }: { children: ReactNode }) {
  return <Provider store={store}>{children}</Provider>;
}

2 Answers 2

1

The server has no access to your persisted data, so SSR will render whatever would be rendered for a newly created Redux store, while your Client will render depending on the persisted data.

There is no way of telling the server what your user has persisted, so the best you can do is either live with this or disable persistance.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for the explanation, but the thing that I don't understand is why is the server even trying to render my client component. My understanding is that, if I write 'use client' on top of the component, then the server would skip the rendering part, because he will know, that it is addressed only to client and not the server, so the ssr would be disabled at this point.
Also I just noticed, that if I remove the part where the products are rendering based of the state of my cart which is using react-persist, there is no hydration error even though I have a number changing in my header based of the number of products in my cart, so now I am completely confused, why is this not triggering the hydration error and the other one does.
Okay got it, it was because I was using conditional rendering there, so for anyone reading this and was confused as I was, it doesn't matter if the text in the elements changes based of your state in redux-state (there would only be warning), but you can't use conditional rendering based of that state, because it would change the application structure so there comes the hydratation error.
Your Client Components will always render on the server when a user first visits the page. If only the RSC would run on the server, there wouldn't be any HTML to ship to the browser. There is a distinction between RSC and SSR of Client Components, and both of these steps happen.
1

I add this in to my store.js file where I defined storage in rootPersistConfig.

store.ts

const isClient = typeof window !== "undefined";
const createNoopStorage = () => {
  return {
    getItem() {
      return Promise.resolve(null as string  |null);
    },
    setItem(_key: string, value: number) {
      return Promise.resolve(value);
    },
    removeItem() {
      return Promise.resolve();
    },
  };
};
const storage =
  isClient
    ? createWebStorage("local")
    : createNoopStorage();
    
const rootPersistConfig = {
  key: "root",
  storage : isClient? storage : createNoopStorage(),
  whitelist: ["auth", "navbar"],
};
const persistedReducer = persistReducer(rootPersistConfig, rootReducer);


export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({ serializableCheck: false }),
});

export const persister = persistStore(store);
export function getReduxState() {


return store.getState();

}

export type App_state = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
const useAppDispatch:() => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<App_state> = useSelector;
export {useAppDispatch};

And in ReduxProvider.tsx I provide store with persistor

ReduxProvider.tsx

"use client";

import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { persister, store } from "./store";

export default function ReduxProvider({
  children
}: {
  children: React.ReactNode;
}) {
  return (
    <Provider store={store}>
      <PersistGate loading={<FallbackLoader />} persistor={persister}>
        {children}
      </PersistGate>
    </Provider>
  );
}

With above code, I don't face error of hydration error because of ReduxProvider

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.