Passing URL for texture through props in react-three-fibre

Viewed 2493

I have recently started using react-three-fibre and I have discovered this example Where the svg image is loaded through the component rather than directly in the function. I wanted to use this idea since I want to reuse the same component but implement different urls to load different textures.

I have tried to copy what this example did but it keeps coming up with the error: Cannot GET /undefined Here is my code:


import * as THREE from "three";
import ReactDOM from 'react-dom'
import React, { Suspense, useState, useRef, useEffect, useMemo } from 'react'
import { Canvas, extend, useLoader, useThree, useFrame } from 'react-three-fiber'



function Box(props, {url}) {
    const [texture] = useLoader(THREE.TextureLoader, url);

    const mesh = useRef()


    const [hover, setHover] = useState(false)


    return (

      <mesh
        {...props}
        ref={mesh}
        castShadow
        rotation={props.rotation} 
        scale={hover ? [1.2, 1, 1.2] : [1, 1, 1]}

        onPointerOver={e => setHover(true)}
        onPointerOut={e => setHover(false)}>

        <boxBufferGeometry attach="geometry" args={[130,.1,120]} />
        <meshStandardMaterial attach="material" map = {texture} transparent = {true} />
      </mesh>

    )
  }


function App() {
  return (
    <Canvas camera={{ position: [5,300,0],  
        fov:60, 
        aspect: window.innerWidth / window.innerHeight, 
        near:1, 
        far: 1000 }}>
        <Suspense fallback={null}>

            <Box position={[150, 10, -340]} rotation = {[0, Math.PI/2,0]} url = {['../../URL']}/>
            <Box position={[0, 0, 0]} />

      </Suspense>

       <directionalLight position = {[1,1,1]} intensity = {[1.7]}/>
    </Canvas>
  )
}


ReactDOM.render(<App />, document.getElementById('root'))



I have also tried to pass the url through props.url instead of using just url but this also comes with a similar error and I don't know how to rectify this. I have looked through the docs here for react-three-fiber and it seems maybe this only works for other loaders? such as Draco or GLTF. But I don't know why it wouldn't work for TextureLoader.

EDIT: Full error: enter image description here enter image description here

So it's not the most useful error as it creates a separate html page saying it cannot get/undefined. It does have something to do with passing the url since if I directly implement the full url inside the function everything works fine. But I don't want to be creating so many different functions. I looked here with someone with a similar error and it suggested that maybe Javascript had set my src to undefined? But it shouldn't since it works perfectly fine if the url isn't passed through props. So i'm guessing my syntax is wrong but I don't know how to correct it.

1 Answers

This line seems like it's causing the issue:

const [texture] = useLoader(THREE.TextureLoader, url);

useLoader will not be able to read url as it is an array, and it will return the texture as an object so destructuring it as an array is not going to work.

The texture url needs to be held in the public folder and accessed however you access public in your environment. I think this is where the cannot GET issue stems from - the file requesting the texture does not have correct access to the public folder.

From there it's just a case of passing the path string down as a prop, and you can do this as a standalone string or as part of an array if necessary. In my example, this was:

<Box url={["/plainmap.jpg"]} />

To access that string in the texture loader you need to specify the index or use the spread operator.

const texture = useLoader(THREE.TextureLoader, ...url);

CodeSandbox

Related