Demo, all content is generated
Question

Next.js 15 dashboard shows old data after I save, need hard refresh

Open · 301 views · asked by jules_v · edited

I have a list of clients on /dashboard. Edit a client in a dialog, server action saves to Supabase, dialog closes, and the list still shows the old name. Hard refresh shows the new name. Windsurf added revalidatePath('/dashboard') at the end of the action, still the same.

The list component:

"use client";
export function ClientList({ initialClients }) {
  const [clients, setClients] = useState(initialClients);
  ...
}
What I’ve tried

revalidatePath, router.refresh() after the action, export const dynamic = 'force-dynamic' on the page.

Comment

4 answers

dev_ana · edited

Your revalidate probably works fine. The bug is useState(initialClients): the initial value is only read on the first render. When the server sends fresh initialClients, React ignores it because the state already exists.

If you don't need to edit the list locally, drop the state and render the prop directly:

export function ClientList({ clients }) {
  return clients.map(...);
}

If you do need local state (optimistic updates), look at useOptimistic instead of copying props into state.

Comment
Oh. That's it for the list. But the client detail page next to it has the same problem and doesn't use useState, so something else is going on there jules_v · edited
Post the detail page code? Is it reading through a fetch with a cache option or through supabase-js? dev_ana · edited
mei_lin · edited

For the detail page: revalidatePath('/dashboard') only revalidates that exact path. The detail page is /dashboard/clients/[id], so revalidate that too, or use revalidatePath('/dashboard', 'layout') to revalidate everything under it.

Comment
katja_s · edited

Once it works, write a small Playwright test: edit a client, assert the list shows the new name without reload. This exact bug tends to come back when an AI "refactors" the list component.

Comment
aiko_n · edited

Quick way to confirm dev_ana's diagnosis: add key={JSON.stringify(initialClients)} on <ClientList> temporarily. If the list updates now, it was the state copy. Then do the proper fix, the key trick is a hack.

Comment