Search code examples
reactjsreact-hooksthree.jsreact-three-fiberreact-three-drei

react-three-fiber & drei useTexture hooks error


error: Uncaught R3F hooks can only be used within the Canvas component!

error location: const terrainTexture = useTexutre(url);

error code:

import { OrbitControls, Sky, useTexture } from '@react-three/drei';
import { Canvas } from '@react-three/fiber';
...

function App() {
  
  const terrainTexture = useTexture('/Environments/Tile/Tile_2048.png');

  return (
    <Canvas>
...
      <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -2, 0]}>
        <planeBufferGeometry args={[100,100]}/>
        <meshStandardMaterial map={terrainTexture}/>
      </mesh>
...
    </Canvas>
  );
}

export default App;


This code 'useTexture' works fine. What's the difference with the code above?

import { useGLTF, useAnimations, useTexture } from '@react-three/drei'
...
export default function ModelAnim({ ...props }) {
...
  const bakedTexture = useTexture('/Characters/Textures/Character_Texture_1024.png')

  useEffect(() => {
...
  }, [])

  return (
    <group ref={group} {...props} dispose={null}>
...
      <skinnedMesh
        geometry={nodes.Character.geometry}
        material={materials.Mat_Character}
        skeleton={nodes.Character.skeleton}
      >
        <meshStandardMaterial map={bakedTexture} map-flipY={false}/>
      </skinnedMesh>
    </group>
  )
}

useGLTF.preload('/Character.gltf')

Solution

  • You can only use React Three Fiber hooks inside the Canvas component. Make a new component that uses the hook, then render that new component inside the Canvas component, like this:

    function Scene() {
      const terrainTexture = useTexture('/Environments/Tile/Tile_2048.png');
    
      return (
        <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -2, 0]}>
          <planeBufferGeometry args={[100,100]}/>
          <meshStandardMaterial map={terrainTexture}/>
        </mesh>
      );
    }
    
    function App() {
      return (
        <Canvas>
          <React.Suspense fallback={<></>}>
            <Scene />
          </React.Suspense>
        </Canvas>
      );
    }