在 React 中渲染 Threejs 使我在 HTML 中的根元素消失

Rendering Threejs in React dissapears my root element in HTML

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

THREE.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
}

这是我的 three.js 代码,我在 React

中做了什么

反应

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 是我的标记组件,当我打开控制台时,我在任何地方都看不到我的 Landing 元素,但在 React 工具中我看到了,我不知道如何解决这个问题

您要删除 Three.JS 组件中的 document.body,这就是正文仅包含 canvas 的原因。您可能希望使用对元素的引用而不是定位 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;