Next.js Discord

Discord Forum

NextJS App Routing - modal that persists on refresh

Unanswered
Chinese perch posted this in #help-forum
Open in Discord
Chinese perchOP
Forwardig this question as I really want to know the answer to this.

"I've looked into the Modal method described on this page in the NextJS docs , and at the answers for Stack Overflow questions like this one, but in all of these examples, when the page is refreshed the modal just appears as its own route, without the original content behind it. Is there a way I can set up the folder structure in such a way that:

1. There is a page, e.g. /lorem, with a list and a button on it

2. A user clicks the button

3. The URL changes to e.g. /lorem/new, and a modal appears above the list

4. If the user refreshes the page, the modal remains, but so does the list behind it.

I've have managed to achieve this using layout.tsx to render the list, a page.tsx that returns null to handle the /lorem route, and a nested new/page.tsx to render the modal. However this brings about other issues relating to access to searchParams etc, and just generally feels very hacky, to have a layout acting as a page and a page returning null. So a more 'proper' way to do this would be ideal."

https://stackoverflow.com/questions/78055876/nextjs-app-routing-modal-that-persists-on-refresh

15 Replies

@Chinese perch Forwardig this question as I really want to know the answer to this. "I've looked into the Modal method described on this page in the NextJS docs , and at the answers for Stack Overflow questions like this one, but in all of these examples, when the page is refreshed the modal just appears as its own route, without the original content behind it. Is there a way I can set up the folder structure in such a way that: 1. There is a page, e.g. /lorem, with a list and a button on it 2. A user clicks the button 3. The URL changes to e.g. /lorem/new, and a modal appears above the list 4. If the user refreshes the page, the modal remains, but so does the list behind it. I've have managed to achieve this using layout.tsx to render the list, a page.tsx that returns null to handle the /lorem route, and a nested new/page.tsx to render the modal. However this brings about other issues relating to access to searchParams etc, and just generally feels very hacky, to have a layout acting as a page and a page returning null. So a more 'proper' way to do this would be ideal." https://stackoverflow.com/questions/78055876/nextjs-app-routing-modal-that-persists-on-refresh
I would use the client to control the open and close of the specific modal. I would create a MyModal Component or however you will call it. Inside I access useQueryState to safe the open state of my modal inside the url and when it changes to also update the url without making a new request to the server. The modal open and close is normal, like I would handle everything clientside (because the modal is clientside) and the state is saved inside the url (thought useQueryState)
Chinese perchOP
Problem.. if you control and render the model as a client component, what happens when you pass in your ServersideComponentThatFetches is that it starts fetching its data before the client modal is ever opened. Which is why the modal needs to be controlled server side I believe. Haven't found a way yet to pass a server component that fetched to a client component modal without server fetching starting while the modal is closed
@Chinese perch Problem.. if you control and render the model as a client component, what happens when you pass in your ServersideComponentThatFetches is that it starts fetching its data before the client modal is ever opened. Which is why the modal needs to be controlled server side I believe. Haven't found a way yet to pass a server component that fetched to a client component modal without server fetching starting while the modal is closed
well, first things first: the server component will be passed as children so it stays a server component. Next, we can also read searchParams serverside. Then you can change the state of your modal, disable shallow routing to make a new request when closing and opening to render the new data and finally you have a component that only shows serverside fetched data when it's open
Chinese perchOP
I've made this work using the url to keep ?modal=true state and keeping the modal a server component before, but without shallow routing the entire page in the background also rerenders and refetches its data when the url changes. I think I might need to make 2 codesandboxes - 1 for client side modal with Server ComponentThatFetches component passed as child/prop and one where the modal is also a server component, thus no need to pass the child ServerComponentThatFetches by prop and thus no fetching prior of showing the modal. The problem with the latter is the same as you suggest - then you need to use the url for state modal=true and disable shallow routing and then the pagei nthe background rerenders and refetches its data everytime you toggle the modal
Chinese perchOP
The reason for me asking is that I have a shopping cart modal and I had some server components from other places in the checkout that I wished to just drop inside the cart modal, but since since the component I want to drop in is a server component it starts fetching immediately and not waiting for the modal to open. So I guess what you're saying is that either you handle this toggling within the url and accept that the page in the background is refetching/rerendering every time you toggle the modal - or alternatively you accept you cannot reuse your server components inside the modal, and make a client side variant and only do client components inside the modal? Either way, bummer...
@Chinese perch The reason for me asking is that I have a shopping cart modal and I had some server components from other places in the checkout that I wished to just drop inside the cart modal, but since since the component I want to drop in is a server component it starts fetching immediately and not waiting for the modal to open. So I guess what you're saying is that either you handle this toggling within the url and accept that the page in the background is refetching/rerendering every time you toggle the modal - or alternatively you accept you cannot reuse your server components inside the modal, and make a client side variant and only do client components inside the modal? Either way, bummer...
yea, my cart PreviewCartComponent looks like this: https://pastebin.com/sTvtch16
As you can see, I take the current state from the url (so I can controll it from other components in my case) and I fetch the data only when the component is mounted (useQuery). Then I fetch the stuff clientside. The getCurrentCartDetails methods just verifies, that the user has access to the cart and then just calls the serverside function. Like that I can reuse the same component. Pretty nice if you ask me and works perfectly
Chinese perchOP
Thanks man. But honestly if its just gonna stay a client modal I prefer to just open/close it with a provider. I don't consider that to be any more difficult than using the url, and then I avoid accidentally fucking up with search that also uses the query string 😄 But yeah both ways work. A bit disappointed though, that I'm in a situation where I can't reuse my server component inside the modal, since to my understanding "reuse" was the whole selling point of colocating all data fetching inside server components
that I'm in a situation where I can't reuse my server component inside the modal
technically you can like I described herehttps://nextjs-forum.com/post/1259016602251296840#message-1259048175981953037
Chinese perchOP
I don't understand. Without shallow routing were back to the problem of rerendering/refetching the page behind the modal when toggling the modal on off and changing the search params..
Chinese perchOP
Even if the data is cached serverside I still think it screams "anti pattern" to rerender and rely on server cached data just to show/hide a modal. I guess I need to accept fetching client side inside the modal
Chinese perchOP
Rq probably. Haven't tried swr. Ideally I would have hoped that next provided the tools needed to fetch and cache data bot server and client side. Oh well I guess I got my answer on this... Unfortunately what I want to be able to do is simply not possible. Thanks for taking the time to discuss this with me.