I’m trying to understand how to handle modals opening/closing with server components. Previously, with client components, I would just lift the state up to my Layout
:
export default function Layout({ children }) {
const [showPopup, setShowPopup] = useState(true)
return (
<>
<Popup showPopup={showPopup} setShowPopup={setShowPopup} />
<div>{children}</div>
</>
)
And then show/hide my popup according to this state. However, with server components, I can’t do that anymore. To make it work, I would need to "use client"
at the top to make it a client component, but then the whole app would be a client component (because that’s my root layout).
I want the root layout to be a server component to allow the app to leverage infrastructure toward better performance and overall user experience.
So how do you handle showing or hiding a modal without relying on useState and client components ? This case is so common that I’m probably missing something obvious, but I can’t find the answer.
2
Answers
Using a wrapper component
A time ago i saw somewhere in Next documentation that to use client side components in Layout you need to put the component in other file with "use client" and import it in your layout file
Using next’s dynamic feature
if it dont work you can try to use dynamic with ssr property but i dont know if this will work
You can’t have client interactivities, like opening a modal, or client-specific code like
useState
without having a Client Component. That has been said,not because
Layout
is marked as a Client Component, everything that’s rendered by it will be. As you can read on the doc, thechildren
prop of a Client Component can be a Server Component:And in this part of the doc, they do not warn about having a
Layout
as a Client Component, as it’s ok:So since your
Layout
doesn’t seem to render anything else than the popup andchildren
, you can make it a Client Component:But if you have some stuff in the layout that needs to be rendered on the server, move the popup in a client wrapper component, like so: