You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-three-fiber useTexture报仅能在Canvas内使用错误排查

问题说明

报错信息

  • 报错内容:Uncaught R3F hooks can only be used within the Canvas component!
  • 报错触发位置:const terrainTexture = useTexutre(url);
    报错对应代码:
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;

参考正常运行代码

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')

核心差异解答

两段代码的核心区别是R3F(React Three Fiber)相关hook的调用位置是否在Canvas组件提供的上下文范围内:

  • @react-three/fiber和@react-three/drei提供的所有hook(包括useTexture、useGLTF、useFrame等),都依赖Canvas组件注入的React Context,只有Canvas的后代组件才能访问到对应的上下文资源,直接在渲染Canvas的父组件里调用这些hook,会因为拿不到上下文直接抛出题目中的错误。
  • 报错代码里,useTexture写在App组件中,而App组件本身是渲染<Canvas>的父组件,调用hook时还处于Canvas上下文外部,不符合调用规则,因此报错。
  • 可正常运行的代码里,useTexture写在ModelAnim组件内部,而ModelAnim是作为子组件被放在<Canvas>标签内渲染的,调用hook时已经处于Canvas的上下文覆盖范围内,符合R3F的hook调用要求,因此可以正常运行。

修复方案

把调用R3F hook、渲染3D对象的逻辑抽离成独立子组件,放到Canvas内部渲染即可,修复示例:

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

// 抽离Canvas内部的场景子组件
function Terrain() {
  // 在Canvas子组件内调用hook,符合规则
  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>
      <OrbitControls />
      <Sky />
      <Terrain />
    </Canvas>
  );
}

export default App;

内容的提问来源于stack exchange,提问作者Ban

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.16 16:15:41