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

React中使用Three.js的GLTFLoader加载3D模型后如何获取引用?

解决方案

你可以通过 React 提供的 useRef 或者 useState 来存储 gltf.scene 的引用,根据使用场景二选一即可:


方案1:使用 useRef 存储(推荐)

模型引用属于不需要触发组件重渲染的可变值,用 useRef 存储更符合性能要求,引用在组件生命周期内不会失效:

import { useRef, useEffect } from 'react';
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const Render = () => {
  // 声明存储模型的ref
  const modelRef = useRef(null);
  const canvasRef = useRef(null);

  useEffect(() => {
    const scene = new THREE.Scene();
    // 此处省略相机、渲染器初始化逻辑
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer({canvas: canvasRef.current});
    renderer.setSize(window.innerWidth, window.innerHeight);

    const loader = new GLTFLoader();
    loader.load('scene.gltf', function (gltf) {
      gltf.scene.scale.set(.1, .1, .1);
      gltf.scene.position.set(.1, 4.1, .1);
      scene.add(gltf.scene);
      // 把模型实例赋值给ref的current属性
      modelRef.current = gltf.scene;
    }, undefined, function (error) {
      console.error(error);
    });

    // 后续操作模型直接访问modelRef.current即可,比如动画循环逻辑
    const animate = () => {
      requestAnimationFrame(animate);
      // 模型加载完成后再操作,避免空引用报错
      if (modelRef.current) {
        modelRef.current.rotation.y += 0.01;
      }
      renderer.render(scene, camera);
    }
    animate();

    // 组件卸载时清空ref、销毁实例避免内存泄漏
    return () => {
      modelRef.current = null;
      renderer.dispose();
    }
  }, [])

  return <canvas ref={canvasRef} />
}

如果需要把模型暴露给父组件操作,可以配合 forwardRef + useImperativeHandle 把引用转发出去:

// Render组件定义时用forwardRef包裹
const Render = forwardRef((props, ref) => {
  const modelRef = useRef(null);
  // 把内部模型引用同步到外部传入的ref
  useImperativeHandle(ref, () => ({
    getModel: () => modelRef.current
  }))
  // 剩余初始化逻辑和上方一致
})

// 父组件调用示例
const App = () => {
  const renderRef = useRef(null);
  // 父组件内直接操作模型
  const handleRotateModel = () => {
    const model = renderRef.current?.getModel();
    if (model) model.rotation.x += Math.PI / 2;
  }
  return <>
    <Render ref={renderRef} />
    <button onClick={handleRotateModel}>旋转模型</button>
  </>
}

方案2:使用 useState 存储

如果你需要模型加载完成后触发组件重渲染(比如渲染加载状态、显示模型控制按钮),可以用 useState 存储:

import { useState, useEffect } from 'react';

const Render = () => {
  const [model, setModel] = useState(null);
  const canvasRef = useRef(null);

  useEffect(() => {
    const scene = new THREE.Scene();
    // 省略相机、渲染器初始化逻辑
    const loader = new GLTFLoader();
    loader.load('scene.gltf', function (gltf) {
      gltf.scene.scale.set(.1, .1, .1);
      gltf.scene.position.set(.1, 4.1, .1);
      scene.add(gltf.scene);
      // 存储模型到state
      setModel(gltf.scene);
    });
    // 操作模型直接用state即可,记得做空判断
    const animate = () => {
      requestAnimationFrame(animate);
      if (model) {
        model.rotation.y += 0.01;
      }
      renderer.render(scene, camera);
    }
    animate();
  }, [model]) // 要把model加入依赖数组

  // 可以根据model是否存在渲染不同内容
  return <>
    {!model && <div className="loading">模型加载中...</div>}
    <canvas ref={canvasRef} />
  </>
}

注意事项

  • 所有操作模型的逻辑都要加空判断,避免模型还没加载完成时报空指针错误
  • 组件卸载时要记得销毁模型、清空引用,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:15:04