My application renders blog posts with your typical post route like /post/[postId]/page.js
. The post route is a server component that implements logic more or less like this
fetch post from database
check if user has permission to see post
return
<PostNavigation />
<PostContents />
Notice: each post gets its own unique navigation.
This works fine for a Desktop layout, but now I’m trying to implement a responsive mobile layout that behaves like this example from Mintlify.
My challenge is that I want to use the same Navigation component in two very different parts of the DOM.
My root layout looks like this
// src/app/layout.js
export default async function RootLayout({ children }) {
return (
<html>
<body>
<Header />
<main>
{ children }
</main>
</body>
</html>
)
}
and my component tree can be visualized like this
app (root)
/
/
Header post route <- post data is fetched here
(client) (server)
/
/
PostNavigation PostContent
(server) (server)
This leads to the real crux of my problem…
The mobile navigation component needs to live inside the Header
, but all the data and logic to create the navigation comes from the post route. I’m confused how to achieve my end goal given this constraint.
Idea 1
One possible solution is to render the navigation server side, for Desktop clients. Then hack together some JS script that identifies the client’s viewport width and manipulates the DOM accordingly. This is nice because the navigation is created server-side and all the logic to render it is in one place. But it’s bad because I’m manipulating the DOM outside of React, and I’m worried about hydration errors and screen flickering.
Idea 2
Another solution is to render two identical copies of the navigation and let them both live in the DOM at the same time. I can easily use CSS to show/hide one or the other based on the viewport width. But here the challenge is, How exactly do I render the mobile navigation? Keep in mind that all the data and logic happens inside the post route, but the mobile nav needs to live in the Header component.