无法在 Three.js React 组件中读取 null 的属性(读取“宽度”)

问题描述 投票:0回答:1

我有一个 Three.js 应用程序,但遇到了问题。我有几个文件:

main.js:
它看起来与this视频中的代码完全一样。我所做的只是将所有内容包装到一个函数中,这样我就可以动态加载 5 个 3D 模型,而不是创建 5 个执行相同操作的 js 文件。

React 组件:

import { displayObject } from "../main"

export default function Atraction() {
  setTimeout(() => { displayObject(myArgs) }, 3000)
  return (
    <canvas className="webgl-1"></canvas>
  )
}

我得到错误:

无法读取 null 的属性(读取“宽度”)

它指的是我要访问的

canvas
元素。我该怎么办?

reactjs three.js 3d
1个回答
0
投票

所以,很难从小片段中准确地弄清楚你的代码是什么样子的。但是,您提供的内容可能会得到改进。如果页面加载时间超过 3 秒(例如网速较慢),会发生什么情况? setTimeout 将中断,因为 html 尚未呈现。另外,如果他们的计算机在 500 毫秒内加载对象,你真的希望人们必须等待 3 秒才能加载对象吗?

useEffect 在 DOM 渲染完成或重新加载时立即运行。可以肯定地说我们只想建立场景一次,所以我们可以在 useEffect 钩子的开始使用一个守卫来确保它只运行一次(当组件第一次渲染时)。

此外,对于 React 函数式组件,我们可以使用 useRef 来获取 DOM 的钩子。虽然从技术上讲,我们可以使用组件的 id 来呈现我们的 ThreeJS 代码,但使用 useRef() 钩子会告诉每个程序员我们稍后将编辑 DOM——它传达了有助于其他程序员阅读的意图。

let rendered = false;

export function Component() {
  const ref = useRef() // this allows us to refer to the dom element once it has been created

  // useeffect happens as soon as Component() has rendered to html
  useEffect(() => {
    if (rendered) { // this makes sure the scene isn't created more than once even if Component() changes/re-renders
      return;
    }
    rendered = true;

    const scene = new THREE.Scene();
    const renderer = new THREE.Renderer(... etc.);

    // ... setup scene/camera/renderer ect.

    // best to separate loading/adding-to-scene out of one function to avoid brittle code
    const car = loadObject('etc/car.gltf');
    scene.add(car)
    const house = loadObject('etc/house.gltf');
    scene.add(house)

    // since the useEffect only runs once dom has rendered, ref will now refer to the dom 
    ref.current.appendChild(renderer.domElement)

  });

  return <div ref={ref} ></div>
}

function loadObject(objectLocation) {
  
   // load object at objectLocation

   return loadedObject
  
}

另外,如果我没记错的话,

    ref.current.appendChild(renderer.domElement)

自己创建一个新的画布组件并将其放入目标组件中。因此,根组件(如我所展示的)可能最好只是一个

<div />
。 (需要引用)

因为我还没有看到你的其余代码:如果这对你没有帮助,请发布更多代码,我会更新我的答案以更好地帮助你。

© www.soinside.com 2019 - 2024. All rights reserved.