I'm using NextJs 13 and I spent many hours trying to make my Strapi menu static once build.
I added a Layout to _app.js and a Menu.js component inside.
Unfortunately I recently found out that getStaticProps only works on pages and not in components.
Does anyone have a solution other than passing the menu data in each getStaticProps of each page?
I also will have a side bar on each page with data from Strapi
Thank you in advance
#Static content
25 messages Β· Page 1 of 1 (latest)
Are you using the app router or the traditional approach?
I'm don't accepted experimental app folder.
And for the route I think using the traditional way.
I have my index.js, [page].js & [post].js
I created a wrapper for getStaticProps but I have to use it on all pages.
export function withMenu(getStaticPropsFunc) {
return async function (context) {
const menuPromise = getMenuData();
const pagePropsPromise = getStaticPropsFunc ? getStaticPropsFunc(context) : { props: {} };
const [menuItems, pageProps] = await Promise.all([menuPromise, pagePropsPromise]);
return {
props: {
menuItems,
...pageProps.props,
},
revalidate: Math.max(pageProps.revalidate || 0, 60),
};
};
}```
I think the approach outlined here should work for you: https://nextjs.org/docs/basic-features/layouts#single-shared-layout-with-custom-app
For the data fetching, you can use getInitialProps inside your _app.js, which should cover your use case as it's for populating the initial values for a component. So after SSG/SSR your menu should be static in the page.
Your <Menu /> component needs to be in your <App /> component and accept the menu content via props. These menu props need to be returned from getInitialProps.
Thank you Tobias I will try this right now
Feel free to let me know how it goes π
_app should look like this right ?
function App({ Component, pageProps, menuItems}) {
useEffect(() => {
require("bootstrap/dist/js/bootstrap.bundle.min.js");
}, []);
return (
<Layout menuItems={menuItems}>
<Component {...pageProps} />
</Layout>
)
}
App.getInitialProps = async () => {
const menuItems = await getMenuData();
return { menuItems}
}
export default App
I think menuItems will be contained in pageProps
It's working
Thank you very much. I spend half a day to find the wrapper way...
It's better like that π
Can I ask you one more thing @shell spruce ?
Sure!
I'm new on nextjs and sometime when there is an issue like miss import or variable that don't exist or wrong json return, I feel that it's hard to debug, the messages are not accurate most of the time. Should I setup something to debug ? Actually i'm only using npm run dev.
What editor are you using?
vscode
Install this plugin: https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint It highlights everything incorrect while you type, so you can fix it before saving the file π
Also, would you be interested in learning another way to solve your problem?
Thank you so much I will install that !
Yes please !
So getInitialProps disables automatic static optimization in Next. Pages with that function can't be static, they will always be rendered for each request. Since we added this function to _app.js, this has huge implications because I'd expect your app can't be static this way. (https://nextjs.org/docs/advanced-features/automatic-static-optimization)
You could try to get around this with next export, but this removes a large chunk of cool Next features, so you also probably don't want that π (https://nextjs.org/docs/advanced-features/static-html-export)
Your initial approach is actually good because it adds the getMenuData query in a clean way. Problem is that this didn't work because Next needs the getStaticProps function, I don't think you can wrap it. But what you still could do is create a utility function you call inside getStaticProps to get the menu data. To streamline this even further, you could create a <Page /> component that renders the menu and the page content. So your [post].js would basically become something like this:
export function Post(props) {
return <Page {...props} />
}
export const getStaticProps = async ({ params }) {
// Fetch menu data
const menuItems = await getMenuData();
// Fetch your page content
const pageContent = getPageContent();
return {
props: {
menuItems,
pageContent
}
}
}
And <Page /> would be something like this:
export default function Page({menuItems, pageContent}) {
return <>
<Menu items={menuItems} />
<main>{pageContent}</main> // Probably too simple :D
</>;
}
I hope this isn't too hard to follow π This way you could have a menu and your app still could be static. If this works for you depends on your use case though.
Thank you so much for all the explanation ! Indeed I will need to keep my pages statics for performance !
And make a wrapper worked for me !
You can try on you side for future use case π
const urlParamsObject = {
filters: {
slug: "home",
},
populate: "deep",
}
const queryString = qs.stringify(urlParamsObject);
const { data } = await api.get(`/pages${queryString ? `?${queryString}` : ""}`);
const pageData = data.data[0];
return { props: { data: pageData } };
}
export default HomePage;
export const getStaticProps = withMenu(getStaticPropsIndex);```
Awesome stuff, I'm glad this works for you!