SSR Issue When Using Redux to Update Layout Header in Next.js
Unanswered
Archin Modi posted this in #help-forum
I have the following setup in my Next.js app:
- layout.tsx:
- Makes a global header API call.
- Displays the header/navigation.
- Page-level API calls:
- Fetch page-specific data.
- Includes a headerType value that determines which header should display.
I need the headerType from the page API to dynamically update the header that lives inside layout.tsx.
I’m using Redux with a makeStore setup (SSR-friendly pattern), but I’m still running into issues:
- On the first server render, the header doesn’t have the correct type.
- The Redux state only updates on the client side.
How can I keep SSR working and dynamically render the correct header type from the start?
Do I need to dispatch setHeaderType in getServerSideProps / getServerSideProps (or generateStaticParams in Next.js 13/14) to hydrate the store?
- layout.tsx:
- Makes a global header API call.
- Displays the header/navigation.
- Page-level API calls:
- Fetch page-specific data.
- Includes a headerType value that determines which header should display.
I need the headerType from the page API to dynamically update the header that lives inside layout.tsx.
I’m using Redux with a makeStore setup (SSR-friendly pattern), but I’m still running into issues:
- On the first server render, the header doesn’t have the correct type.
- The Redux state only updates on the client side.
How can I keep SSR working and dynamically render the correct header type from the start?
Do I need to dispatch setHeaderType in getServerSideProps / getServerSideProps (or generateStaticParams in Next.js 13/14) to hydrate the store?
// store.ts
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { createWrapper } from 'next-redux-wrapper';
const headerSlice = createSlice({
name: 'header',
initialState: { type: 'default' },
reducers: {
setHeaderType: (state, action) => {
state.type = action.payload;
},
},
});
export const { setHeaderType } = headerSlice.actions;
export const makeStore = () =>
configureStore({
reducer: {
header: headerSlice.reducer,
},
});
// [locale]/layout.tsx (if using app router)
'use client';
export default function Layout({ children }) {
const headerType = useSelector((state: RootState) => state.header.type);
return (
<>
<Header type={headerType} />
<main>{children}</main>
</>
);
}
// page.tsx (server component with SSR data fetching)
import { setHeaderType, wrapper } from './store';
export const getServerSideProps = wrapper.getServerSideProps((store) => async () => {
const pageData = await fetchPageData();
store.dispatch(setHeaderType(pageData.headerType));
return {
props: { pageData },
};
});