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

React+Three.js集成3D模型遇R3F钩子报错:仅能在Canvas内使用

解决R3F: Hooks can only be used within the Canvas component! 错误

问题重现

使用React + Three.js(react-three-fiber)渲染3D模型时,收到错误提示:

R3F: Hooks can only be used within the Canvas component!

已将<Model1 />置于<Canvas>标签内,但网站仍无法加载,核心代码如下:

Home.js 核心代码

<Canvas
  className={`w-full h-screen bg-transparent ${isRotating ? 'cursor-grabbing' : 'cursor-grab'}`}
  camera={{ near: 0.1, far: 1000, position: [0, 0, 10], fov: 10 }}
>
  <ambientLight intensity={0.4} />
  <pointLight position={[10, 5, 10]} intensity={2} />
  <directionalLight position={[1, 1, 1]} intensity={2} /> 
  <spotLight position={[10, 5, 10]} angle={0.15} penumbra={1} intensity={2} />
  <Suspense fallback={loader}>
    <Model1 
      position={modelPosition}
      rotation={[0.1, 4.7077, 0]}
      scale={modelScale}
      isRotating={isRotating}
      setIsRotating={setIsRotating}
    />
  </Suspense>
</Canvas>

// 其他相关代码
useEffect(() => {
  adjustModelForScreenSize();
  const handleResize = () => adjustModelForScreenSize();

  window.addEventListener('resize', handleResize);
  return () => window.removeEventListener('resize', handleResize);
}, []);

const loader = <div style={{ textAlign: 'center' }}>Loading...</div>;

Model1.js 代码

import React, { useRef } from "react";
import { useGLTF } from "@react-three/drei";
import { useFrame } from "@react-three/fiber";

const Model1 = ({ position, rotation, scale, isRotating, setIsRotating, ...props }) => {
const modelRef = useRef();
const { scene } = useGLTF("/character_mannequin_male.glb");

useFrame(() => {
if (isRotating && modelRef.current) {
modelRef.current.rotation.y += 0.01;
    }
  });

return (
    <primitive
object={scene}
ref={modelRef}
position={position}
rotation={rotation}
scale={scale}
      {...props}
    />
  );
};

useGLTF.preload("/character_mannequin_male.glb"); // 错误根源

export default Model1;

错误原因

useGLTF.preload()属于react-three-fiber生态的方法,必须在Canvas组件的上下文环境内执行。你把它写在了Model1组件的外部,脱离了Canvas的上下文,触发了R3F的钩子使用限制。

解决方案

将useGLTF.preload()移到Model1组件内部,确保它处于Canvas的上下文范围内。

修改后的Model1.js

import React, { useRef } from "react";
import { useGLTF } from "@react-three/drei";
import { useFrame } from "@react-three/fiber";

const Model1 = ({ position, rotation, scale, isRotating, setIsRotating, ...props }) => {
  const modelRef = useRef();
  // 将预加载调用移到组件内部
  useGLTF.preload("/character_mannequin_male.glb");
  const { scene } = useGLTF("/character_mannequin_male.glb");

  useFrame(() => {
    if (isRotating && modelRef.current) {
      modelRef.current.rotation.y += 0.01;
    }
  });

  return (
    <primitive
      object={scene}
      ref={modelRef}
      position={position}
      rotation={rotation}
      scale={scale}
      {...props}
    />
  );
};

export default Model1;

补充:实现鼠标拖拽旋转功能

如果你需要鼠标拖拽旋转模型,推荐使用@react-three/drei提供的OrbitControls,它能快速实现拖拽、缩放等交互,无需手动维护isRotating状态:

在Home.js的Canvas内添加OrbitControls:

import { OrbitControls } from '@react-three/drei';

<Canvas ...>
  {/* 其他灯光组件 */}
  <OrbitControls 
    enableZoom={false} // 按需关闭缩放
    enablePan={false} // 按需关闭平移
  />
  <Suspense fallback={loader}>
    <Model1 ... />
  </Suspense>
</Canvas>

添加后用户即可直接拖拽模型旋转,同时可以移除自己手动维护的isRotating相关逻辑,简化代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 05:45:40