Next.js Discord

Discord Forum

`router.refresh()` only works once in pages router

Answered
Cuban Crocodile posted this in #help-forum
Open in Discord
Cuban CrocodileOP
I am using pages router and useRouter from next/navigation for refreshing the page when an action is taken by user and a certain condition is met.

When the action is taken, the page refreshes properly. But when i take the same action again, the page wont refresh.

I can confirm that my function is being called cuz it shows a toast before the refresh. So it is router.refresh() that's the only thing bugging out.

i have the following handler in a parent component:
  const router = useRouter()
  const handleDelete = async (asset: Pick<AssetData, "id" | "name">) => {
    const isConfirmed = await deleteModal(`Are you sure you want to delete ${asset.name}?`)
    if (!isConfirmed) {
      return
    }

    const response = await deleteAsset(asset.id)
    toast({
      variant: response.success ? "default" : "destructive",
      title: response.message,
    })

    if (!response.success) {
      return
    }

    router.refresh()
  }


which is used inside a child:
                  <Button
                    onClick={async (e) => {
                      e.stopPropagation()
                      handleDelete(asset)
                    }}


the function is being passed to the child component through a context:
const { handleDelete } = useContext(MyContext)
Answered by Jboncz
useEffect(() => {
  const newGrouped = groupAssets(assets)
  const newNodes = generateNodes(newGrouped)
  setNodes(newNodes)
}, [assets, setNodes])


Can you try adding this
View full answer

120 Replies

Are you receiving any errors?
import { useRouter } from 'next/navigation'


Are you importing the proper router?
import { useRouter } from 'next/router' is for the pages router
They are seperate functions
Cuban CrocodileOP
it is indeed the proper router, and no errors
What are you expecting when you refresh because when refreshing through the router like that it does a dom compare and only updates components with new data.
you wont actually see the broswer refresh
I would recommend checking your network tab when you call the router.refresh() and see whats happening
Cuban CrocodileOP
i am essentially deleting a thing from a list.

So when i delete one thing, the page updates and the deleted thing disappears. that's what i expect.

but when i delete another thing, i get a toast saying everything was successful but the page is not updated. this the problem.
doing a hard refresh brings us back to square one
So first time you delete it works properly, second time it doesnt?
That sounds like a logic issue somewhere down the line
if you delete thing 1 then hit f5 and delete thing 2 does it work?
Cuban CrocodileOP
yup
Is this 'thing' something in a database or client side thing?
Cuban CrocodileOP
database
okay so next question. Delete thing 1 (successful), delete thing 2 (unsuccesful)... when deleting thing 2 does the item get removed from the database?
but the client side isnt updated?
Cuban CrocodileOP
yes it does
exactly
Hrmmmm.
    if (!response.success) {
      return
    }

    router.refresh()


Humor me and add a console.log in the if statement and then one right ebfore the router.refresh()
Cuban CrocodileOP
aye
and then repeat the scenario
@Jboncz js if (!response.success) { return } router.refresh() Humor me and add a console.log in the if statement and then one right ebfore the router.refresh()
    if (!response.success) {
      console.log('delete failuire');
      return
    }


    console.log('delete success');
    router.refresh()
should only ever get one.
just make sure its success both times
Gotta start with the basic
Cuban CrocodileOP
the forward ref problem is because the edit button's component is fucked is not created properly. (im not sure if this can cause refreshing to fail tho)
@Jboncz just make sure its success both times
Cuban CrocodileOP
that does seem to be the case
Hrmmm, this is an interesting one let me run a test
on my side
Cuban CrocodileOP
just to be sure i removed the problematic edit button, and the behaviour didn't change so we can rule that out
Gotcha.
What mechanism is re-fetching the data on a router.refresh()?
can you verify the data your getting back on the client side is right?
Cuban CrocodileOP
there's a server component that loads the data on page load
that's the parent of everything
export default async function Page() {
  const { user } = await getSessionData()
  const canDelete = await userHasPermission("deleteAssets", user)
  const canEdit = await userHasPermission("editAssets", user)
  const assets = (await loadAssets()).map(transformAssets)

  return (
    <div className="react-flow-container w-full" style={{ height: "calc(100vh - 78px)" }}>
      <View assets={assets} canDelete={canDelete} canEdit={canEdit} />
    </div>
  )
}
the view component is client component right?
Cuban CrocodileOP
yes, and its opting out of ssr
useEffect(() => {
  console.log(assets)
},[assets])
Cuban CrocodileOP
const View = dynamic(() => import("./view").then((mod) => mod.default), { ssr: false })
throw this in your client component
and try again
Cuban CrocodileOP
hmm you are suggesting that the server is not sending updated data
Make sure that its passing to the client component correctly both times.
Maybe
idk
Im throwing darts at the wall lol
its how I would troubleshoot at this point
Cuban CrocodileOP
mhmm yeah im also stumped, so lemme give it a shot
Basically im just slowly recommending things that would eliminate a variable, eventually we will find the culprit
Cuban CrocodileOP
so i start off with six items. correct. i delete one, i get 5 items in console and 5 items in view. correct. finally (after second delete) i get 4 items in console but 5 items in view.
Interesting...
Cuban CrocodileOP
lemme try adding a key them, maybe that react is getting confused during diffing
oh xD yeah add a key for sure.
even if its just an index
Still weird it works the first time though
actually dont set it as the index, set it as the id for the item
Cuban CrocodileOP
yeah i used unique id's but that didnt resolve it
Im stumped.... hrmmmm! Let me think for a second. Wish I could play with it locally
I dont have time to setup an actual repro
Can you send me the View component and let me see?
Cuban CrocodileOP
aye no worries, i have a temp alternate which is to do a full reload with window.location.reload() and people from my company wont give a fuck. but its annoying that i can't do it properly
@Jboncz Can you send me the View component and let me see?
Cuban CrocodileOP
sure, no company secret here lol
Thats what I figured since your actually doing it properly and passing from the server component 😛
Cuban CrocodileOP
good thing i haven't broken down this file yet
well its 5am here now, so im gonna take a snooze. i will keep the ticket open
one last 'tip' for your workaround, you can use router.push(router.asPath)
to do a hard refresh
Cuban CrocodileOP
ah lemme give it a shot
little better dx than the window ap
api
imo
Cuban CrocodileOP
it says router.asPath doesn't exist on approuter... did i fucked up
xdtcfvgjbhknlkml
I forgot
LOL
app router vs pages router. you would have to use the usePath() hook
oops
maybe not better dx then
useEffect(() => {
  const newGrouped = groupAssets(assets)
  const newNodes = generateNodes(newGrouped)
  setNodes(newNodes)
}, [assets, setNodes])


Can you try adding this
Answer
last thing
then you can go to sleep 😂
Cuban CrocodileOP
ah i would have kms lmao
aye lets do that
I guess its _setNodes, my b
Cuban CrocodileOP
i got you
ayeee that resolved it
woo
Cuban CrocodileOP
now the question is how and why
Probably because refresh is refreshing the data, but not calling to set the nodes again
It MIGHT be a ReactFlow issue to some degree.
react having a hard time diffing the complex item
so we essentially are doing it for them
at least thats my though
thought* thats why I recommended it.
Cuban CrocodileOP
hmm so what's happening is:
- router refresh is updating the data
- but also keeping the state
- then trying to run the diff
- then messing it up
Im guessing.... or there is something more fundamental we dont quite understand completely. Like I said, I didnt make a full reproduction so when you refresh the page using the router does it rerun everything in the client component? Idk?

 
  const initialNodes = generateNodes(grouped)
  const [nodes, _setNodes, onNodesChange] = useNodesState(initialNodes)


this is essentially the problem child, for some reason its not seeing a difference between re-renders
Im somewhat speculating.
Cuban CrocodileOP
will have to dig deeper into what refresh is doing exactly to figure out where its failing
Yeah, but for now.... at least you dont have to hard refresh! 🙂
Cuban CrocodileOP
yess thank you so much for that
np!
GL going forward
Also let me know if you figure out the root cause.
I am curious
@Jboncz Also let me know if you figure out the root cause.
Cuban CrocodileOP
will do
Have a good one, 5am is a late night
Cuban CrocodileOP
we are facing some issues revalidation in other places as well, and one of our engineers is looking specifically into that
If your using the same workflow
Cuban CrocodileOP
i feel so
will probably write about it if i do figure it out
for now, good night
night!
Is this normal?
While not ideal, it's a common scenario when working with complex, stateful third-party components. Many developers encounter this when working with data visualization libraries, map components, or other complex UI elements.
Why isn't refresh causing the nodes to regenerate?
router.refresh() is updating your data source (the assets prop), but it's not directly connected to React Flow's internal state. React Flow doesn't know it needs to regenerate nodes based on the new assets unless we explicitly tell it to do so.
I took a shot in the dark and asked Claude for an explanation of why this is fixing it and why refresh isnt working properly.