【问题标题】:Rendering Threejs in React dissapears my root element in HTML在 React 中渲染 Threejs 使我在 HTML 中的根元素消失
【发布时间】:2021-10-05 01:29:06
【问题描述】:

我正在尝试在 Typescript react 中使用 Three.js,我渲染十二面体图形和随机星星,我想使用 React 为我的three.js 添加一些标记,但是当我将 Three.js 画布渲染为 HTML 时,它消失了我的根 div,我无法添加其他一些组件

三个.JS

import * as THREE from "three";

export function ThreeCanvas() {
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

  const renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);

  document.body.innerHTML = "";
  document.body.appendChild(renderer.domElement);

  const geometry = new THREE.DodecahedronBufferGeometry(1.7, 0);
  const material = new THREE.MeshStandardMaterial({
    color: "#00FF95",
  });

  const Stars = () => {
    const starGeometry = new THREE.SphereGeometry(0.1, 24, 24)
    const starMaterial = new THREE.MeshStandardMaterial({color: 0xffffff})
    const star = new THREE.Mesh(starGeometry, starMaterial)

    const [x, y, z] = Array(3).fill(1).map(() => THREE.MathUtils.randFloatSpread(70))
    star.position.set(x, y, z)

    scene.add(star)
  }

  Array(200).fill(100).forEach(Stars)

  const light = new THREE.PointLight(0xffffff)
  light.position.set(20, 20, 20)
  scene.add(light)

  camera.position.z = 5;
  camera.position.x = 3.5

  const Figure = new THREE.Mesh(geometry, material);

  scene.add(Figure);

  const animate = () => {
    requestAnimationFrame(animate);
    Figure.rotation.x += 0.01;
    Figure.rotation.y += 0.01;
    renderer.render(scene, camera);
  };

  animate();

  window.addEventListener("resize", () => {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
  });
  
  return null
}

这是我在 react 中所做的 three.js 代码

反应

import ReactDOM from "react-dom"
import { ThreeCanvas } from "./Components/Three";
import Landing  from "./Components/Landing";
import "./Style/Style.css"

const FirstSection = () => {
  return (
    <div className="container">
      <Landing />
      <ThreeCanvas />;
    </div>
  );
}

ReactDOM.render(<FirstSection />, document.getElementById("root"));

当我打开控制台时,Landing 是我的标记组件

【问题讨论】:

    标签: reactjs typescript three.js


    【解决方案1】:

    您正在删除 Three.JS 组件中的 document.body,这就是 body 仅包含画布的原因。您可能希望使用对元素的引用而不是定位 document.body,这样它就不会干扰 DOM 结构,这就是您的降价不显示的原因。根据经验,您永远不应该通过文档与 DOM 进行交互。

      document.body.innerHTML = "";
    

    我已经快速重构了 Three.JS 组件以使用 React 元素引用,以便您可以添加额外的标记。

    重构 ThreeCanvas 组件

    import * as React from "react";
    import * as THREE from "three";
    
    export function ThreeCanvas() {
      const ref = React.useRef();
      const [loaded, setLoaded] = React.useState(false);
    
      React.useEffect(() => {
        if (!loaded && ref) {
          const scene = new THREE.Scene();
          const camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
          );
    
          const renderer = new THREE.WebGLRenderer();
          renderer.setSize(window.innerWidth, window.innerHeight);
    
          const geometry = new THREE.DodecahedronBufferGeometry(1.7, 0);
          const material = new THREE.MeshStandardMaterial({
            color: "#00FF95"
          });
    
          const Stars = () => {
            const starGeometry = new THREE.SphereGeometry(0.1, 24, 24);
            const starMaterial = new THREE.MeshStandardMaterial({
              color: 0xffffff
            });
            const star = new THREE.Mesh(starGeometry, starMaterial);
    
            const [x, y, z] = Array(3)
              .fill(1)
              .map(() => THREE.MathUtils.randFloatSpread(70));
            star.position.set(x, y, z);
    
            scene.add(star);
          };
    
          Array(200).fill(100).forEach(Stars);
    
          const light = new THREE.PointLight(0xffffff);
          light.position.set(20, 20, 20);
          scene.add(light);
    
          camera.position.z = 5;
          camera.position.x = 3.5;
    
          const Figure = new THREE.Mesh(geometry, material);
    
          scene.add(Figure);
    
          const animate = () => {
            requestAnimationFrame(animate);
            Figure.rotation.x += 0.01;
            Figure.rotation.y += 0.01;
            renderer.render(scene, camera);
          };
    
          const resize = () => {
            renderer.setSize(window.innerWidth, window.innerHeight);
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
          };
    
          animate();
          ref.current.appendChild(renderer.domElement);
          window.addEventListener("resize", resize);
          setLoaded(true);
          return () => window.removeEventListener("resize", resize);
        }
      }, [ref, loaded]);
    
      return <div ref={ref} />;
    }
    
    export default ThreeCanvas;

    打字稿版本:ThreeCanvas.tsx

    import * as React from "react";
    import * as THREE from "three";
    
    export function ThreeCanvas() {
      const ref = React.useRef<HTMLDivElement>(null);
      const [loaded, setLoaded] = React.useState(false);
    
      React.useEffect(() => {
        if (!loaded && ref.current) {
          const scene = new THREE.Scene();
          const camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
          );
    
          const renderer = new THREE.WebGLRenderer();
          renderer.setSize(window.innerWidth, window.innerHeight);
    
          const geometry = new THREE.DodecahedronBufferGeometry(1.7, 0);
          const material = new THREE.MeshStandardMaterial({
            color: "#00FF95"
          });
    
          const Stars = () => {
            const starGeometry = new THREE.SphereGeometry(0.1, 24, 24);
            const starMaterial = new THREE.MeshStandardMaterial({
              color: 0xffffff
            });
            const star = new THREE.Mesh(starGeometry, starMaterial);
    
            const [x, y, z] = Array(3)
              .fill(1)
              .map(() => THREE.MathUtils.randFloatSpread(70));
            star.position.set(x, y, z);
    
            scene.add(star);
          };
    
          Array(200).fill(100).forEach(Stars);
    
          const light = new THREE.PointLight(0xffffff);
          light.position.set(20, 20, 20);
          scene.add(light);
    
          camera.position.z = 5;
          camera.position.x = 3.5;
    
          const Figure = new THREE.Mesh(geometry, material);
    
          scene.add(Figure);
    
          const animate = () => {
            requestAnimationFrame(animate);
            Figure.rotation.x += 0.01;
            Figure.rotation.y += 0.01;
            renderer.render(scene, camera);
          };
    
          const resize = () => {
            renderer.setSize(window.innerWidth, window.innerHeight);
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
          };
    
          animate();
          ref.current.appendChild(renderer.domElement);
          window.addEventListener("resize", resize);
          setLoaded(true);
          return () => window.removeEventListener("resize", resize);
        }
      }, [ref, loaded]);
    
      return <div ref={ref} />;
    }
    
    export default ThreeCanvas;

    【讨论】:

    • 也非常感谢你,如果有人使用 Typescript React,我会添加一些快速修复,在 Typescript React 上使用这段代码你会得到类型错误,Object is possibly 'undefined' ref.current.appendChild(renderer.domElement) 来解决这个问题只需写@ 987654326@手动消除错误
    • @callmenikk 我已经用 Typescript 的正确类型更新了答案,我建议使用它而不是设置任何类型。
    • 非常感谢
    猜你喜欢
    • 1970-01-01
    • 2022-01-25
    • 2018-01-15
    • 2021-05-01
    • 2018-02-25
    • 2016-03-14
    • 1970-01-01
    • 2017-08-18
    • 1970-01-01
    相关资源
    最近更新 更多