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

React Three中useRef获取Three.js对象返回null问题求助

React Three Fiber中ref获取Three.js对象为null的原因及解决方案

核心原因

你遇到的问题本质是React Three Fiber(R3F)的组件生命周期与普通React DOM组件不同:

  • 普通DOM元素的ref是在React渲染流程的commit阶段(DOM节点创建完成后)直接赋值给ref.current,因此空依赖的useEffect(首次渲染后执行)能立即拿到有效值。
  • R3F的<Canvas>组件是异步初始化Three.js渲染环境的:它会在React首次渲染完成后,再单独启动Three.js的渲染器、场景、相机等实例的创建流程。<PerspectiveCamera>这类R3F组件对应的Three.js实例,要等到Canvas的异步初始化完成后才会被创建并绑定到ref上,所以你在首次渲染的useEffect里拿到的是null。你的猜测完全正确——就是3D场景的异步初始化导致ref无法立即绑定。

解决方案

1. 使用R3F专属的useFrame钩子

useFrame是R3F提供的、在Three.js渲染循环启动后执行的钩子,此时所有Three.js实例都已初始化完成,能稳定拿到ref:

import { useRef } from 'react';
import { Canvas, PerspectiveCamera, useFrame } from '@react-three/fiber';

function App() {
  const cameraRef = useRef<THREE.PerspectiveCamera>(null);

  // useFrame会在渲染循环启动后执行,此时ref已绑定
  useFrame(() => {
    if (cameraRef.current) {
      console.log('Camera instance:', cameraRef.current);
      // 这里可以安全操作相机
    }
  });

  return (
    <div className="h-screen w-screen">
      <Canvas shadows>
        <PerspectiveCamera
          ref={cameraRef}
          makeDefault
          position={[0, 2, 3]}
          fov={75}
        />
      </Canvas>
    </div>
  );
}

2. 监听ref的变化(备选)

如果不需要在渲染循环中执行,可以用useEffect监听cameraRef.current的变化,但要注意处理初始null的情况:

import { useRef, useEffect } from 'react';
import { Canvas, PerspectiveCamera } from '@react-three/fiber';

function App() {
  const cameraRef = useRef<THREE.PerspectiveCamera>(null);

  useEffect(() => {
    if (cameraRef.current) {
      console.log('Camera ready:', cameraRef.current);
    }
  }, [cameraRef.current]);

  return (
    <div className="h-screen w-screen">
      <Canvas shadows>
        <PerspectiveCamera
          ref={cameraRef}
          makeDefault
          position={[0, 2, 3]}
          fov={75}
        />
      </Canvas>
    </div>
  );
}

3. 直接获取默认相机(更简便)

因为你给相机加了makeDefault属性,还可以通过R3F的useThree钩子直接获取默认相机,无需手动绑定ref:

import { useThree } from '@react-three/fiber';
import { Canvas, PerspectiveCamera } from '@react-three/fiber';

function App() {
  const { camera } = useThree();

  useEffect(() => {
    // camera就是已初始化的PerspectiveCamera实例
    console.log('Default camera:', camera);
  }, [camera]);

  return (
    <div className="h-screen w-screen">
      <Canvas shadows>
        <PerspectiveCamera
          makeDefault
          position={[0, 2, 3]}
          fov={75}
        />
      </Canvas>
    </div>
  );
}

内容的提问来源于stack exchange,提问作者Berkay Çırak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 06:07:41