Three.js canvas 的 React 组件正在工作,但不是每次都有效

React component with Three.js canvas is working but NOT every time

所以我有以下反应组件,它允许我将 three.js canvas 附加到 HTMLDivElement 类型的 ref 对象:

import { useEffect, useRef } from "react";
import * as THREE from 'three';

export default function Viewport() {
  const mountRef = useRef<HTMLDivElement>(null);
  const { current } = mountRef;

  useEffect(() => {
    if (!current) { return; }

    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(75, current.clientWidth / current.clientHeight, 0.1, 1000);
    var renderer = new THREE.WebGLRenderer();
    const { domElement } = renderer;
    renderer.setClearColor(0xfff5ff,1)
    renderer.setSize(current.clientWidth, current.clientHeight);
    current.appendChild(domElement);

    var geometry = new THREE.BoxGeometry(1, 1, 1);
    var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
    var cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    camera.position.z = 5;
    var animate = function () {
      requestAnimationFrame(animate);
      cube.rotation.x += 0.01;
      cube.rotation.y += 0.01;
      renderer.render(scene, camera);
    };
    
    animate();

    return () => {
      current.removeChild(domElement);
    };

  }, []);

  return (
    <div ref={mountRef} style={{width: '100%', height: '100%'}}>
    </div>
  );
}

该组件有效,但不是每次我安装它!这是“大部分时间”的输出: 如果我只是添加:

    console.log(current);

代码可以正常工作,HTMLDivElement 对象将打印到控制台! 我在这里错过了什么?

这里是项目的 CodeSandBox link: https://codesandbox.io/s/unruffled-burnell-3if54?file=/src/Viewport.tsx

您正在关闭 mountRefcurrent 属性 的陈旧副本。 current的初始值为null,也就是下一行第一次抓取的值。然后 React 呈现您的组件并设置 current 以引用 div,然后 然后 您的 useEffect 回调被调用——但它仍然有 null.

相反,在 useEffect 回调中使用更新后的 属性;看评论:

export default function Viewport() {
  const mountRef = useRef<HTMLDivElement>(null);
  // Don't grab `current` here

  useEffect(() => {
    // Grab it here
    const { current } = mountRef;
    if (!current) { return; }
    // ...