【问题标题】:How to solve "addEventListener" TypeError of null in ReactJS?如何解决 ReactJS 中 null 的“addEventListener”TypeError?
【发布时间】:2021-07-10 10:20:59
【问题描述】:

我正在尝试使用 Google 的模型查看器来加载 3D 模型。它有一个按钮。但我希望该按钮在模型完全加载后可见。所以,我曾经使用这个 Vanilla JavaScript 代码

<script>
   const modelViewer = document.querySelector("model-viewer");
   const button = document.getElementById("my_ar_button");

   modelViewer.addEventListener("load", function() {
   button.style.display = "block";
   });
</script>

现在我打算在 ReactJS 中使用它,这就是它的样子

const modelViewer = document.querySelector("model-viewer");
const button = document.getElementById("my_ar_button");
    
modelViewer.addEventListener("load", function() {
button.style.display = "block";
});

<model-viewer 
src="https://modelviewer.dev/shared-assets/models/reflective-sphere.gltf"
alt="A 3D model of an astronaut"
ar ar-modes="webxr scene-viewer quick-look"
ar-scale="auto"
quick-look-browsers="safari chrome"
ios-src="https://modelviewer.dev/shared-assets/models/Astronaut.usdz"
loading="eager"
poster="https://modelviewer.dev/assets/poster-astronaut.png"
autoplay
camera-controls
>
  <button id="my_ar_button" class="my_ar_button" slot="ar-button">Show AR</button>
</model-viewer>
                

我的 CSS

.my_ar_button {
display: none;
}

我已经使用脚本标签添加了模型查看器

<Helmet>
 <script
 type="module"
 src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"
 async
 >
 </script>
</Helmet>

但它给了我这个错误

TypeError: Cannot read property 'addEventListener' of null

【问题讨论】:

  • 利用refs 访问DOM 元素。检查 useRef。
  • 欢迎来到 SO。您的问题中缺少一些细节,因此难以回答。请您向我们展示您如何将model-viewer 导入您的项目。是通过脚本标签还是通过 npm?您提供了一些代码,但没有上下文。该代码在哪里运行?在一个组件中?如果是这样,请显示它的代码。
  • @spender 我已经更新了我的问题。感谢您的建议。

标签: reactjs react-hooks model-viewer


【解决方案1】:

您需要在 React 包装器中控制 &lt;model-viewer&gt; 元素。见react-model-viewer,这是他们的包装

const useModelLoader = (type, src): ModelData => {
  const loader = useMemo(() => getLoader(type), [type]);

  const [model, setModel] = useState(undefined);
  const [modelCenter, setModelCenter] = useState<THREE.Vector3>(undefined);
  const [error, setError] = useState(undefined);
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    loader.load(
      // resource URL
      src,
      // called when the resource is loaded
      model => setModel(model),
      // called while loading is progressing
      ({ loaded, total }) => setProgress((loaded / total) * 100),
      // called when loading has errors
      error => setError(error)
    );
  }, [loader, src]);

  // get the center of the model
  useEffect(() => {
    if (!model) {
      return;
    }

    const box = new THREE.Box3();

    box.setFromObject(model.scene);

    const center = new THREE.Vector3();

    box.getCenter(center);

    setModelCenter(center);
  }, [model]);

  return { model, modelCenter, progress, error };
};

第二个useEffect() 依赖于model,所以你可以对按钮做同样的事情。这将是 modelViewer.addEventListener("load", function() { 的 React 等价物

const [showButton, setShowButton] = useState(false);

useEffect(() => {
  if (model) {                // when model has a value, the loader has completed
    setShowButton(true);      // now show the button
  }
}, [model]);

const Button = showButton ? <button...> : null;  // use this to wrap <button>

【讨论】:

  • 感谢您的帮助。但看起来react-model-viewer 不再被维护了。而model-viewer 已经有一个事件Load
  • 不维护也没关系,我贴的代码给大家展示了如何将非reactmodel-viewer组件集成到react的工作方式中,包括load事件(在哪里说// called when the resource is loaded)。你了解 React 组件吗,如果是的话,以上内容应该足以让你继续前进。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-03
  • 2018-01-24
  • 2020-06-26
  • 2021-06-13
  • 1970-01-01
相关资源
最近更新 更多