Next.js Discord

Discord Forum

Maintaining Client-Side Modal State with Server Action Revalidation in Next.js

Unanswered
Tomistoma posted this in #help-forum
Open in Discord
TomistomaOP
I'm currently in the process of migrating a project from Next.js' traditional pages router to the new app router. As part of this migration, I'm aiming to transition my client-side API calls to server actions. However, I've hit a snag with one of my client components, specifically RedeemRewardButton. This component plays a crucial role in managing a reward redemption process, which involves guiding the user through a sequence of modals.

Workflow Description:
1. Initial Interaction: The user clicks on the RedeemRewardButton, which opens a confirmation modal.
2. Server Action: Upon user confirmation, the component triggers a server action (redeemRewardAction). This action makes an API call to my backend, processes the response, and returns a standard success or error response.
3. Page Revalidation Issue: The issue arises when I call revalidatePath('/') within my server action. This is intended to refresh user data (fetched server-side before page load) to reflect the newly redeemed reward and updated point balance.

Problem: The call to revalidatePath('/') causes a full page refresh, leading to the unintended closure of the success modal that should remain visible post-action.

Context:
- The data refresh is crucial as it updates the client with the latest reward data and point balance.
- I'm considering shifting this to a client-side API call. However, for consistency and the advantages of server actions (like direct access to environment variables and headers), I'm keen on using server actions across my project.
- Was previously using SWR for this.

Question:
How can I effectively refresh the stale data via my server action without disrupting the state of client-side modals? Is there a recommended approach in Next.js to achieve a seamless user experience where the data is updated in the background, but the client-side modal state is preserved?

Any suggestions or insights on this matter would be greatly appreciated. Thank you!

16 Replies

@Tomistoma I'm currently in the process of migrating a project from Next.js' traditional pages router to the new app router. As part of this migration, I'm aiming to transition my client-side API calls to server actions. However, I've hit a snag with one of my client components, specifically `RedeemRewardButton`. This component plays a crucial role in managing a reward redemption process, which involves guiding the user through a sequence of modals. **Workflow Description:** 1. **Initial Interaction**: The user clicks on the `RedeemRewardButton`, which opens a confirmation modal. 2. **Server Action**: Upon user confirmation, the component triggers a server action (`redeemRewardAction`). This action makes an API call to my backend, processes the response, and returns a standard success or error response. 3. **Page Revalidation Issue**: The issue arises when I call `revalidatePath('/')` within my server action. This is intended to refresh user data (fetched server-side before page load) to reflect the newly redeemed reward and updated point balance. **Problem**: The call to `revalidatePath('/')` causes a full page refresh, leading to the unintended closure of the success modal that should remain visible post-action. **Context**: - The data refresh is crucial as it updates the client with the latest reward data and point balance. - I'm considering shifting this to a client-side API call. However, for consistency and the advantages of server actions (like direct access to environment variables and headers), I'm keen on using server actions across my project. - Was previously using SWR for this. **Question**: How can I effectively refresh the stale data via my server action without disrupting the state of client-side modals? Is there a recommended approach in Next.js to achieve a seamless user experience where the data is updated in the background, but the client-side modal state is preserved? Any suggestions or insights on this matter would be greatly appreciated. Thank you!
Hi, have you tried creating the modal with intercepting routes?
https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes#modals
@Ray Hi, have you tried creating the modal with intercepting routes? https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes#modals
TomistomaOP
No actually, haven't come across those, thanks for sharing! Have skim-read the documentation and will dig deeper shortly, but my immediate concern is that it might not be appropriate for "action" type modals that are triggered through business logic/flows. I wouldn't necessarily want someone to be able to directly link to a modal that requires prior confirmation for instance.
TomistomaOP
Yeah, I see that – might be a good solution for now at least. I'll give it a go. Still open to other options though! Previously I was handling these kind of state mutations with SWR, and instead of a full page refresh, I'd invalidate the data from my /users/authenticated end-point. That's what I'm trying to recreate here in a context where the data comes in from the server instead.
TomistomaOP
That's a decent suggestion too. I think it's the shift in mindset around re-validating data that's catching me out more than anything here though. The modal issue itself is kind of a symptom of that. SWR mutations were pretty clear-cut in that respect.
@Tomistoma I feel like it's a traditional issue of managing state while there might be page reloads
usually they are done in JS, when you mean a page refresh, you mean a new request/response roundtrip?
I need to double check but when JS is enabled the Server Actions tends to behave more like an SPA
it will receive an RSC payload instead of refreshing the page
=> this means you can store your modal state in a layout above the page
in a React context
because the "page refresh" is only a client one so it won't rerender the layout but just the page
Let me know if that's wrong I've never tested this way, cool use case
TomistomaOP
@Eric Burel I'll DM you instead of polluting this thread 👍