title: How to properly hydrate Redux state in NextJS on page refresh?
body: <p>The problem I'm having is hydrating the user data from local storage on app reload/page refresh.</p>
  <p>In my project I am using NextJS for frontend, and for support libraries I am using <code>redux-toolkit</code> for redux management across the application and <code>next-redux-wrapper</code> for state hydration for the wrapped pages.</p>
  <p>The user can log in, and in that case I store the <code>isLoggedIn</code> boolean in local storage and in the redux state. Depending on the <code>isLoggedIn</code> boolean value I change the <code>Navbar</code> component styles (the <code>Navbar</code> is included directly in <code>_app.tsx</code>).</p>
  <p>When the user refreshes any page the <code>isLoggedIn</code> boolean is not loaded into the state but is present in local storage.</p>
  <p>In the past I have been using <code>redux-persist</code> but I have opted out of using it because the <code>PersistGate</code> was blocking the UI from rendering until the persisted data is fetched from storage which conflicts with the idea of SSR.</p>
  <p>Currently I have the <code>isLoggedIn</code> loading problem fixed by using the <code>App.getInitialProps</code> method in <code>_app.ts</code> which then results in hydration from <code>next-redux-persist</code> being called for each and every page loaded, but this introduces another problem: all pages are now server side rendered and there is no NextJS' static page optimisation.</p>
  <p>Is there any way to not lose static page optimisation from NextJS, not use the <code>redux-persist</code> library and still be able to hydrate the client side store when any page is refreshed?</p>
  <p>Current code structure (some code is omitted for simplicity):</p>
  <code>file: _app.tsx</code>
  <pre class="lang-js prettyprint-override"><code>import { wrapper } from 'store';
  
  const MyApp = ({ Component, pageProps }: AppProps) =&gt; {
    return (
      &lt;&gt;
        &lt;Navbar /&gt;
        &lt;Component {...pageProps} /&gt;
      &lt;/&gt;
    );
  };
  
  
  MyApp.getInitialProps = async (appContext) =&gt; {
    const appProps = await App.getInitialProps(appContext);
  
    return { ...appProps };
  };
  
  export default wrapper.withRedux(MyApp);
  </code></pre>
  <code>file: store.ts</code>
  <pre class="lang-js prettyprint-override"><code>import {
    combineReducers,
    configureStore,
    EnhancedStore,
    getDefaultMiddleware
  } from '@reduxjs/toolkit';
  import { createWrapper, MakeStore } from 'next-redux-wrapper';
  import userReducer from 'lib/slices/userSlice';
  
  const rootReducer = combineReducers({
    user: userReducer
  });
  
  const setupStore = (context): EnhancedStore =&gt; {
    const middleware = [...getDefaultMiddleware(), thunkMiddleware];
  
    if (process.env.NODE_ENV === 'development') {
      middleware.push(logger);
    }
  
    return configureStore({
      reducer: rootReducer,
      middleware,
      // preloadedState,
      devTools: process.env.NODE_ENV === 'development'
    });
  };
  
  const makeStore: MakeStore = (context) =&gt; setupStore(context);
  export const wrapper = createWrapper(makeStore, {
    debug: process.env.NODE_ENV === 'development'
  });
  </code></pre>
  <code>file: userSlice.ts</code>
  <pre class="lang-js prettyprint-override"><code>import { createSlice } from '@reduxjs/toolkit';
  import { HYDRATE } from 'next-redux-wrapper';
  
  const initialState = {
    isLoggedIn: false
  }
  
  export const userSlice = createSlice({
    name: 'user',
    initialState,
    reducers: {
      login: (state) =&gt; {
        state.isLoggedIn = true;
        localStorage.setItem('loggedInData', { isLoggedIn: true });
      }
    },
    extraReducers: (builder) =&gt; {
      builder
        .addCase(HYDRATE, (state, action: any) =&gt; {
          if (typeof window !== 'undefined') {
            const storedLoggedInData = localStorage.getItem('loggedInData');
            if (storedLoggedInData != null &amp;&amp; storedLoggedInData) {
              const parsedJson = JSON.parse(storedLoggedInData);
              state.isLoggedIn = parsedJson.isLoggedIn ?? false;
            } else {
              state.isLoggedIn = false
            }
          }
        });
    }
  });
  
  export const isLoggedInSelector = (state: RootState) =&gt; state.user.isLoggedIn;
  
  export default userSlice.reducer;
  </code></pre>
  <code>file: Navbar.tsx</code>
  <pre class="lang-js prettyprint-override"><code>import { useSelector } from 'react-redux';
  import { isLoggedInSelector } from 'lib/slices/userSlice';
  
  export default function Navbar() {
     const isLoggedIn = useSelector(isLoggedInSelector);
     return (
      &lt;div className={`${ isLoggedIn ? 'logged-in-style' : 'logged-out-style'}`}&gt;...&lt;/div&gt;
     )
  }
  </code></pre>