Three.js react js/next js 重复内容
Three.js react js/next js duplicated content
我在 react(next js) 中使用 Three.js,我创建的 Mesh 被复制了多次
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,我也没有找到替代方法。
你会想要在 React 中保留有效的东西 useEffect
. This will run on the browser when the component mounts and re-run if its dependency array changes. A dependency would be an immutable value that represents state derived from hooks like useState
。
您也永远不想直接触摸 DOM,因为 React 不会知道您在那里所做的更改,从而导致重复和其他副作用。相反,您可以通过 useRef
挂钩访问带有 refs 的 DOM。这使我们可以使用 canvasRef.current
.
获得 canvas 的可变访问器
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;
请注意 returns 回调的效果。这是一个清理函数,在组件卸载时执行。我们这样做是因为 three.js 将几何体和 material 着色器程序上传到 GPU,这些程序不会被垃圾收集并且会持续存在。由于您必须自己管理生命周期,因此我强烈建议为 three.js 使用渲染器,例如 @react-three/fiber
,这样您就可以更好地使用 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;
这是因为脚本会在组件呈现时运行。所以最好的方法是制作一个 canvas 元素并使用 useEffect
钩子或 componentDidMount
方法,如果它是 class.
但就个人而言,我建议使用 react-three/fiber
或 react-three-next
我在 react(next js) 中使用 Three.js,我创建的 Mesh 被复制了多次
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,我也没有找到替代方法。
你会想要在 React 中保留有效的东西 useEffect
. This will run on the browser when the component mounts and re-run if its dependency array changes. A dependency would be an immutable value that represents state derived from hooks like 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;
请注意 returns 回调的效果。这是一个清理函数,在组件卸载时执行。我们这样做是因为 three.js 将几何体和 material 着色器程序上传到 GPU,这些程序不会被垃圾收集并且会持续存在。由于您必须自己管理生命周期,因此我强烈建议为 three.js 使用渲染器,例如 @react-three/fiber
,这样您就可以更好地使用 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;
这是因为脚本会在组件呈现时运行。所以最好的方法是制作一个 canvas 元素并使用 useEffect
钩子或 componentDidMount
方法,如果它是 class.
但就个人而言,我建议使用 react-three/fiber
或 react-three-next