My 3D objects are not showing after refresh the page

Hi there,
I have an issue. When I go to each room page, I mean “http://localhost:3000/room/1” or “/room/2” and then I see My object. But When I refresh the pages the objects disappear. And show ERROR.

This is my App.js code:

import React from 'react'
import Home from './components/Home'
import { Route, Routes } from 'react-router-dom'
import Navbar from './components/Navbar'
import RoomList from './components/RoomList'
import DataGrid from './components/DataGrid'
import RoomOne from './components/RoomOne'
import RoomTwo from './components/RoomTwo'
import RoomThree from './components/RoomThree'
import RoomFour from './components/RoomFour'
import RoomFive from './components/RoomFive'
import RoomSix from './components/RoomSix'
import RoomSeven from './components/RoomSeven'
import RoomEight from './components/RoomEight'



const App = () => {
  return (
    <>
      <Navbar />
      <Routes>
        <Route path='/' element={<Home />} />
        <Route path='/allRooms' element={<Home />} />

        <Route path='/rooms' element={<RoomList />} />
        <Route path='/dataGrids' element={<DataGrid />} />

        <Route path='/room'>
          <Route path='1' element={<RoomOne />} />
          <Route path='2' element={<RoomTwo />} />
          <Route path='3' element={<RoomThree />} />
          <Route path='4' element={<RoomFour />} />
          <Route path='5' element={<RoomFive />} />
          <Route path='6' element={<RoomSix />} />
          <Route path='7' element={<RoomSeven />} />
          <Route path='8' element={<RoomEight />} />
        </Route>

        <Route path="*" element={<h1>Not found | Please go home</h1>} />
      </Routes>
    </>
  )
}

export default App

This is my one of RoomOne code:

import React, { Suspense } from 'react'
import { Room1 } from "../assets/Room1";
import { Canvas } from '@react-three/fiber';
import { ContactShadows, OrbitControls } from '@react-three/drei';


const RoomOne = () => {
    

    return (


        <div className='eachRoom'>
        <Canvas shadows camera={{ fov: 10, position: [-20, 30, 50] }}>
            <Suspense fallback={null}>
                <ambientLight intensity={0.3} />
                <directionalLight
                castShadow
                receiveShadow
                intensity={0.5}
                position={[-80, 50, -85]}
                shadowNormalBias={0.1}
                shadowCameraLeft={-12}
                shadowCameraRight={12}
                shadowCameraTop={12}
                shadowCameraBottom={-12}
                shadowCameraNear={0.5}
                shadowCameraFar={200}
                />
                <directionalLight
                castShadow
                receiveShadow
                intensity={1}
                position={[30, 100, 90]}
                shadowNormalBias={0.1}
                shadowCameraLeft={-12}
                shadowCameraRight={12}
                shadowCameraTop={12}
                shadowCameraBottom={-12}
                shadowCameraNear={0.5}
                shadowCameraFar={200}
                />
    
                <Room1 />
    
                <ContactShadows />
            </Suspense>
            <OrbitControls enablePan={true} enableZoom={true} enableRotate={true} />
            </Canvas>
        </div>

        
    )
}

export default RoomOne

Here’s the full code in sandbox: weeeeweeeweeee - CodeSandbox

Thank You

it is not recommended to create and destroy the canvas, the threejs webglrenderer etc. this puts so much stress onto the browser and the GC, so much time and memory wasted. this is react, so you can have routes within the canvas, exchange contents and meshes, don’t unmount and re-mount the whole thing from scratch, route changes will be immediate as they should be.

<Canvas>
  <ambientLight />
  <OrbitControls />
  ...
  <Route path='/room'>
    <Route path='1' element={<RoomOne />} />
    <Route path='2' element={<RoomTwo />} />
    <Route path='3' element={<RoomThree />} />
    ...

this will also eliminate hundreds of lines of code because all the canvas content are doubled in each room. lights, controls etc, all that can stay mounted, only the room should load.

another hint, use lazy loading, there’s no reason to load all the rooms at once:

- import RoomOne from './components/RoomOne'
+ const RoomOne = React.lazy(() => import('./assets/Room1'))
1 Like

as for your problem, when i use this url: “./models/room1.glb” and hit refresh, i get

Could not load ./models/room1.glb: Unexpected token '<', "<!DOCTYPE "... is not valid JSON)

when i use “/models/room1.glb” it works.

keep in mind that routing changes the url of your navbar and that also affects how and from where you can fetch assets. i don’t know the specifics of your app but a 404 is a sure sign that paths are incorrect.

1 Like

You mean I should wrap my App.js route inside the Canvas?

Also, it’s really hard to write code for every component. I tried to put all room in 1 file. but it didn’t work properly.
Here’s the code:

import { Canvas } from '@react-three/fiber';
import React, { Fragment, Suspense, useState } from 'react';
import { ContactShadows, OrbitControls } from '@react-three/drei';
import { Route, useParams } from 'react-router-dom';

import { Room1 } from "../assets/Room1";
import { Room2 } from "../assets/Room2";
import { Room3 } from "../assets/Room3";
import { Room4 } from "../assets/Room4";
import { Room5 } from "../assets/Room5";
import { Room6 } from "../assets/Room6";
import { Room7 } from "../assets/Room7";
import { Room8 } from "../assets/Room8";

const Rooms = () => {
    const { id } = useParams();
    const rooms = [
      Room1,
      Room2,
      Room3,
      Room4,
      Room5,
      Room6,
      Room7,
      Room8
    ];
  
    const Room = rooms[id - 1];
  
    return (
      <div className='eachRoom'>
        <Canvas >
          <Suspense fallback={null}>
            <ambientLight intensity={0.3} />
            <directionalLight
              castShadow
              receiveShadow
              intensity={0.5}
              position={[-80, 50, -85]}
              shadowNormalBias={0.1}
              shadowCameraLeft={-12}
              shadowCameraRight={12}
              shadowCameraTop={12}
              shadowCameraBottom={-12}
              shadowCameraNear={0.5}
              shadowCameraFar={200}
            />
            <directionalLight
              castShadow
              receiveShadow
              intensity={1}
              position={[30, 100, 90]}
              shadowNormalBias={0.1}
              shadowCameraLeft={-12}
              shadowCameraRight={12}
              shadowCameraTop={12}
              shadowCameraBottom={-12}
              shadowCameraNear={0.5}
              shadowCameraFar={200}
            />
  
            <Fragment>{Room}</Fragment>
  
            <ContactShadows />
          </Suspense>
          <OrbitControls enablePan={true} enableZoom={true} enableRotate={true} />
        </Canvas>
      </div>
    )
  }
  
  export default Rooms




i guess. just do the same you did before, just put the routes inside canvas. delete every instance of /src/components/Room*.js

1 Like

I can’t wrap my app.js (route) with canvas.
Its says “Canvas is not part of the THREE namespace! Did you forget to extend? See: React Three Fiber Documentation

I tried to use useEffect in one of the room

import React, { Suspense, useEffect, useState } from 'react'
import { Room1 } from "../assets/Room1";
import { Canvas } from '@react-three/fiber';
import { ContactShadows, OrbitControls } from '@react-three/drei';


const RoomOne = () => {

    const [model, setModel] = useState(null)
    useEffect(() => {
        async function loadModel() {
            try {
            const model = await import('/models/room1.glb')
            setModel(model)
            } catch (error) {
            console.error(error)
            setModel(null)
            }
        }
        loadModel()
        }, [])
    
    if (!model) return <p>Error loading model. Please try again later.</p>
    return (


        <div className='eachRoom'>
        <Canvas shadows camera={{ fov: 10, position: [-20, 30, 50] }}>
            <Suspense fallback={null}>
                <ambientLight intensity={0.3} />
                <directionalLight
                castShadow
                receiveShadow
                intensity={0.5}
                position={[-80, 50, -85]}
                shadowNormalBias={0.1}
                shadowCameraLeft={-12}
                shadowCameraRight={12}
                shadowCameraTop={12}
                shadowCameraBottom={-12}
                shadowCameraNear={0.5}
                shadowCameraFar={200}
                />
                <directionalLight
                castShadow
                receiveShadow
                intensity={1}
                position={[30, 100, 90]}
                shadowNormalBias={0.1}
                shadowCameraLeft={-12}
                shadowCameraRight={12}
                shadowCameraTop={12}
                shadowCameraBottom={-12}
                shadowCameraNear={0.5}
                shadowCameraFar={200}
                />
    
                <Room1 />
    
                <ContactShadows />
            </Suspense>
            <OrbitControls enablePan={true} enableZoom={true} enableRotate={true} />
            </Canvas>
        </div>

        
    )
}

export default RoomOne

But it says this " Module not found: Error: You attempted to import /models/room1.glb which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
You can either move it inside src/, or add a symlink to it from project’s node_modules/."

Do I need to move the object to scr folder ? I mean create a new folder and put the raw glb objects?
Right now glb objects are in public folder

again, exchange contents, not the canvas.

you are doing this:

<Canvas>
  <Canvas>
    <Room />

that’s why you get that error. everything inside <Canvas> is threejs, you can’t mount dom elements in there. you are supposed to mount the threejs contents into the canvas, but your room components have a full <Canvas> in them. delete all these components. only leave /src/assets/Room*.js. and then you can just link them via routes.

1 Like

Hi. Can you please check this: weeeeweeeweeee COPY COPY - CodeSandbox

There I import { Room1 } from "./assets/Room1";

And did this

      <Canvas>
        <Routes>
          <Route path="/qw" element={<Room1 />} />
        </Routes>
      </Canvas>

But there is no OUTPUT.

Even If i use only this

      <Canvas>
        <Suspense fallback="null">
          <Room1 />
        </Suspense>
      </Canvas>

On my app.js, Its still show Nothing

i don’t understand, it’s your project, your canvas worked before, you placed it into your css grids. so why would you not place the new canvas in app.js into the same grid? your canvas had zero height. canvas will take 100% width and 100% height of the next absolute or relative parent, like any other dom node.

but you know that, because once i copy some setup from components/Room*.js

<div className="eachRoom">
  <Canvas camera={{ fov: 10, position: [-20, 30, 50] }}>
    <ambientLight intensity={0.3} />
    ....
    <Room1 />

i see a room.

i think it would be good if you took some more time before relying on external help, i almost feel bad for helping you because this will just damage your learning. try to be a little more inspective: something doesn’t work, why could that be, why did it work before, what is the difference between the new code and the old, etc.

1 Like

Thanks for helping Man. Please don’t get it wrong I’m new. I re-read all your comments and did the code by myself. That’s why I earlier mark your comment as a solution.
I got the solution path from this. Here’s my latest code.
https://codesandbox.io/s/nooooo----------nooooo-0hij48?file=/src/App.js

Please check it and give a review :)) Its possible because you help me :))

Thank you for the GREAT ADVISE. You’re Awesome :smile: