Next.js Discord

Discord Forum

How can I prevent a canvas from re-rendering when changing page

Answered
Afghan Hound posted this in #help-forum
Open in Discord
Afghan HoundOP
My app can be summarized as this:

- A top bar made in react that displays the project name and a locale switcher
- A canvas made from react-unity-webgl. Inside it, the user can change "space", and doing so changes the route so that it can be deep linked and for analytics purposes.
- A hamburger menu in react that displays the list of available spaces (routes)

Routes are defined as follow:
[locale]/[vWebsiteID]/[vSpaceID]

When the user changes the route in the canvas, I want to preserve the canvas from unmounting and re-mounting as there is a transition in the canvas that moves to another space and therefore breaks immersiveness.

I tried putting everything in a layout and make the page.js render almost nothing, but the canvas still re-render.

I tried using the native history API, but the useParams don't get updated if I do so, and I need the param to handle specific logic.

How can I do that?
Answered by Afghan Hound
For anyone having the same issue, I found what's happening:

I had the component holding my canvas inside a Layout to prevent rerenders. But that layout was in fact inside a dynamic route, so here for example:

[locale]/[vWebsiteID]/[vSpaceID]/layout.js

Thing is, in my case only the vSpace changes when the user navigates. Because of that, the layout has to rerender.
So the trick is to put the component holding the canvas where the route doesn't change. In my case I just put it one level above.

Explained here:
https://github.com/vercel/next.js/issues/44793#issuecomment-1382458981
View full answer

11 Replies

I would recommend using query paramater instead of dynamic route
so it should look like
[locale]/[vWebsiteID]/?vSpaceID=abc
Afghan HoundOP
The thing is, this route is already being used in production, and probably bookmarked as well.
([locale]/[vWebsiteID]/[vSpaceID])

Is there really no way of achieving this with the app router other than with query params?

Would the generateStaticParams help in any way considering I already know all of the possible parameters? I am loading all the spaces on app load
Nope, it won't help
[locale]/[vWebsiteID]/?vSpaceID=abc this is the only way to prevent reloading I believe
and if you are concerned about your urls bookmarked in users' browser, we can try permernant redirection
[locale]/[vWebsiteID]/[vSpaceID] => [locale]/[vWebsiteID]/?vSpaceID=abc
Afghan HoundOP
Hmm I see..
So I didn't mention it, but I also have another page after the vSpaceID, so like:

[locale]/[vWebsiteID]/[vSpaceID]/[contentItemID]

That last segment is used for mobile atm, but on desktop at this route:
[locale]/[vWebsiteID]/[vSpaceID]

The user can click on elements in the canvas and it opens a modal with info. This info is the same as on mobile for this route:
[locale]/[vWebsiteID]/[vSpaceID]/[contentItemID]

That would mean I'd have to pass both ids in querystring? Never been a fan of query strings for routing haha
Afghan HoundOP
I wonder though why doesn't the params from useParams get updated when using the native history API 🤔
then you probably need to have contentItemID as query param
Afghan HoundOP
Turns out I found an example at this link:
https://app-router.vercel.app/context

If you look at this part, it never rerenders but keep its state. (I cloned the repo and just showed the border animation)

I was able with my app to make it so that when I change route, that the canvas in my layout doesn't rerender. I still have no clue why it does at some point though...
Afghan HoundOP
For anyone having the same issue, I found what's happening:

I had the component holding my canvas inside a Layout to prevent rerenders. But that layout was in fact inside a dynamic route, so here for example:

[locale]/[vWebsiteID]/[vSpaceID]/layout.js

Thing is, in my case only the vSpace changes when the user navigates. Because of that, the layout has to rerender.
So the trick is to put the component holding the canvas where the route doesn't change. In my case I just put it one level above.

Explained here:
https://github.com/vercel/next.js/issues/44793#issuecomment-1382458981
Answer