【问题标题】:Three.js react js/next js duplicated content三.js react js/next js 重复内容
【发布时间】:2021-11-20 19:39:54
【问题描述】:

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

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;

像这样:

然后控制台选项卡有:

目标是在屏幕上显示 1 个立方体而不滚动(水平和垂直)。

我怀疑是 document.body.appendChild 的问题,我也没有找到替代方法。

【问题讨论】:

    标签: javascript reactjs three.js next.js


    【解决方案1】:

    你会想要在 React 的 useEffect 中保留有效的东西。这将在组件挂载时在浏览器上运行,如果其依赖项数组发生更改则重新运行。依赖项是一个不可变的值,表示从 useState 等钩子派生的状态。

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

    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;
    

    注意效果如何返回回调。这是在组件卸载时执行的清理功能。我们这样做是因为three.js 将几何和材质着色器程序上传到GPU,这些程序不会被垃圾收集并且会持续存在。由于您必须自己管理生命周期,我强烈建议您使用像 @react-three/fiber 这样的 three.js 渲染器,这样您就可以更好地使用 React 生态系统。

    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】:

      这是因为脚本在组件呈现时运行。因此,最好的方法是制作一个画布元素并使用useEffect 钩子或componentDidMount 方法(如果它是一个类)。

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

      【讨论】:

        猜你喜欢
        • 2023-03-08
        • 2015-09-28
        • 1970-01-01
        • 2020-09-02
        • 2021-10-23
        • 2019-06-18
        • 2021-08-10
        • 2021-05-29
        • 1970-01-01
        相关资源
        最近更新 更多