reactjsreact-router-domreact-three-fiberreact-three-drei

React-Three-Fiber Drei canvas not updating/leaving ghost image when route changes


The Problem

I currently have a canvas that covers the entire screen that renders a torus on the home page to a View that tracks to a div in the home page. However, when I click on my navbar to another page and the route changes, the torus is still there even when the div that the View is tracking disappears. The HTML elements position themselves as if the div is not there and upon refreshing the page, the torus disappears.

Torus appearing correctly on the home page This is the torus appear correctly on the home page. See that the "Home" text appears underneath it

Torus staying there even though route changed This is the torus staying there even when the route changed. See that the "Syllabus" text appears at the top

Refreshing the page, the torus is correctly not there on the syllabus page When the page is refreshed, the torus disappears which is the intended response.

Attempted Solutions

I making the View change depending on the route by inserting a <Route> inside the Canvas, but I couldn't do it as it wasn't a Three component.

I also tried to use useLocation() and the useEffect() components to update the position of the torus repeatedly, moving my canvas into its own element and nesting it inside the Routes component. However, I could not find a way to pass multiple references down to the Canvas.

I suspect the issue is because the canvas does not get rerendered when the route changes, however I'm not sure how to force a rerender.

Code

Here is my code

  const ref = useRef()
  const splashView = useRef()

  return (
    <div>
      <BrowserRouter>
        <div ref={ref}>
          <Navbar/>
          <Routes>
            <Route index element={<Home ref={splashView}/>}/>
            <Route path="/home" element={<Home ref={splashView}/>}/>
            <Route path="/syllabus" element={<Syllabus/>}/>
          </Routes>
        </div>
      </BrowserRouter>
      <Canvas eventSource={ref} className={styles.canvas}>
        {/* --------------Home Page-------------- */}
        <View track={splashView}>
          <ambientLight intensity={0.1} />
          <directionalLight color="red" position={[0, 0, 5]} />
          <mesh>
            <torusGeometry/>
            <meshStandardMaterial />
          </mesh>
        </View>
      </Canvas>
    </div>
  );
}

After passing the reference into the component, I use forwardRef() to forward it to a div. I am using react-router-dom for routing.


Solution

  • I suspect you could just render the Canvas with the Home component on its route, and redirect the root index route to "/home" so the code is more DRY (or vice-versa).

    const ref = useRef()
    const splashView = useRef()
    
    return (
      <div>
        <BrowserRouter>
          <div ref={ref}>
            <Navbar />
            <Routes>
              <Route index element={<Navigate to="/home" replace />} />
              <Route
                path="/home"
                element={(
                  <>
                    <Home ref={splashView} />
                    <Canvas eventSource={ref} className={styles.canvas}>
                      <View track={splashView}>
                        <ambientLight intensity={0.1} />
                        <directionalLight color="red" position={[0, 0, 5]} />
                        <mesh>
                          <torusGeometry />
                          <meshStandardMaterial />
                        </mesh>
                      </View>
                    </Canvas>
                  </>
                )}
              />
              <Route path="/syllabus" element={<Syllabus />} />
            </Routes>
          </div>
        </BrowserRouter>
      </div>
    );