首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Three.js react js/next js重复内容

Three.js react js/next js重复内容
EN

Stack Overflow用户
提问于 2021-09-28 19:01:44
回答 2查看 177关注 0票数 1

我在react(next js)中使用Three.js,并且我创建的网格被多次复制

代码语言:javascript
复制
import * as THREE from 'three';


function Index() {
    if (process.browser) {
        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);
        renderer.setPixelRatio(window.devicePixelRatio);
        document.body.appendChild(renderer.domElement);

        console.log(scene.children);
        const geometry = new THREE.BoxGeometry();
        const material = new THREE.MeshBasicMaterial({color: 0x00ff00});
        const cube = new THREE.Mesh(geometry, material);
        scene.add(cube);
        console.log(scene.children);
        camera.position.z = 12;

        renderer.render(scene, camera);
        return <div> </div>
    }
    return null;

}

export default Index;

如下所示:

则控制台选项卡具有:

目标是在没有滚动的情况下在屏幕上显示一个立方体(水平和垂直)。

我怀疑这是由document.body.appendChild决定的,我也没有找到替代它的方法。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-29 05:18:29

您将希望在React的useEffect中保留有效的内容。这将在组件挂载时在浏览器上运行,并在其依赖项数组更改时重新运行。依赖项是一个不可变值,表示从useState等钩子派生的状态。

您也永远不想直接接触DOM,因为React不会知道您在那里所做的更改,这会导致重复和其他副作用。相反,您可以通过useRef钩子访问带有ref的DOM。这让我们可以使用canvasRef.current获得一个可变的画布访问器。

代码语言:javascript
复制
import * as THREE from 'three';
import { useRef, useEffect } from 'react';

function Index() {
  const canvasRef = useRef();

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

    const renderer = new THREE.WebGLRenderer({ canvas: canvasRef.current });

    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(window.devicePixelRatio);

    console.log(scene.children);
    const geometry = new THREE.BoxGeometry();
    const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    console.log(scene.children);
    camera.position.z = 12;

    renderer.render(scene, camera);

    // Cleanup on unmount, otherwise stuff will linger in GPU
    return () => {
      renderer.forceContextLoss();
      renderer.dispose();
      cube.geometry.dispose();
      cube.material.dispose();
    };
  }, []);

  return <canvas ref={canvasRef} />;
}

export default Index;

注意effect是如何返回回调的。这是一个在组件卸载时执行的清理函数。我们这样做是因为three.js会将几何体和材质着色器程序上传到图形处理器,这些程序不会被垃圾回收,并且会一直存在。因为你必须自己管理生命周期,所以我强烈建议你使用像@react-three/fiber这样的three.js渲染器,这样你就可以更好地使用React生态系统。

代码语言:javascript
复制
import { Canvas } from '@react-three-fiber';

function Index() {
  return (
    <Canvas frameloop="demand" camera={{ position: [0, 0, 12] }}>
      <mesh>
        <boxGeometry />
        <meshBasicMaterial color={0x00ff00} />
      </mesh>
    </Canvas>
  );
}

export default Index;
票数 2
EN

Stack Overflow用户

发布于 2021-09-29 05:18:48

这是因为只要组件呈现,脚本就会运行。因此,最好的方法是创建一个画布元素,如果它是一个类,则使用useEffect钩子或componentDidMount方法。

但就我个人而言,我建议使用react-three/fiberreact-three-next

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69367213

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档