How should I handle WebGL context when switching to a new page?

On my personal website, I’m using Next.js with static pages and have set up a DOM and canvas on the homepage. When I switch to another page away from the canvas, I get the warning THREE.WebGLRenderer: Context Lost.

Everything runs fine in real world usage, but I’m wondering if there’s a better way to handle switching to and from the page with the canvas on it.

you should simply not do that, unmounting canvas on route change eventually will crash the tab because you can only open a limited amount of canvases and it’s going to cause memory issues, jank and slowness. instead leave the canvas mounted and exchange contents. with ssr and ssg websites should feel instant, that is established by switching components instead of refreshing the whole page and the same applies to the canvas.

here’s an example of how fast threejs can be in a nextjs routing context: GitHub - pmndrs/react-three-next: React Three Fiber, Nextjs, Tailwind and Styled-components starter

1 Like

It’s difficult to say without seeing your implementation, a link to a live example of your setup would help debug, are you using componentWillUnmount() for instance? There doesn’t seem the need to destroy your webgl context if the site is dynamic and is never actually reloaded

Ahh ok. My site just has a canvas on the front page for a fun visual, but the rest of the site is just basic text and images. I was following that NextJS template, but it seemed more focused on bouncing between canvases.

I haven’t looked into unmounting at all. Everything sort of just works, so I hadn’t thought about mounting and unmounting the context until now. I’m simply navigating away entirely to a new dynamic page and losing the context.

How did you end up solving this, I was doing exactly what you deed with just a cool animation in the homepage.

I’ve done both…

A) Recently I made an app which is essentially a product browser with some 3d media sprinkled around. The instances of canvas occur in many different places and views, small or fullscreen. It made sense to have separate elements (only one is shown at a time) to live naturally alongside the rest of HTML, fully responsive et al. I went out of my way to have comprehensive destroy logic on unmount. Any threejs element that has .remove() or equivalent, nullifying proprietary things and making sure related DOM elements are removed (handled by if condition in framework template). In the end, everything remained smooth when bouncing around views quickly.

B) In another app I’ve done the complete opposite: It had search results displayed in a canvas geographic map (which had webgl optionally). Here the desire was the user could enter “map view” at any time and the UI would transform accordingly and reveal the map visually. Benefit bneing that the map was instantly available. However you have to scrutinize when the map is loaded in the background (routes and views) and if the map is loaded, will it do something kind of task (who knows what) after x amount of time that may affect the user experience? Blah blah. One plus is since the map is fullscreen, I don’t have to worry about layout positioning and responsiveness (well, I did, for map icons and controls).