Hi, I’m having a lot of issues implementing my plain threejs project into a react project. Basically, I have a react app with a bunch of pages and I want one of them to be all threejs-y but I’m struggling a lot with adding controls and getting the cooler parts to work. For reference, here’s my plain threejs project:
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
/**
* Base
*/
// Canvas
const canvas = document.querySelector('canvas.webgl')
// Scene
const scene = new THREE.Scene()
/**
* Object
*/
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
/**
* Fullscreen
*/
window.addEventListener('dblclick', () =>
{
const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement
if(!fullscreenElement)
{
if(canvas.requestFullscreen)
{
canvas.requestFullscreen()
}
else if(canvas.webkitRequestFullscreen)
{
canvas.webkitRequestFullscreen()
}
}
else
{
if(document.exitFullscreen)
{
document.exitFullscreen()
}
else if(document.webkitExitFullscreen)
{
document.webkitExitFullscreen()
}
}
})
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.z = 3
scene.add(camera)
// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
/**
* Animate
*/
const clock = new THREE.Clock()
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()
And then here is what I have so far on the react project one:
import React, { Component } from "react";
import { createRoot } from "react-dom/client";
import * as THREE from "three";
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
export default class SimVis extends Component {
componentDidMount() {
var canvas = document.querySelector('canvas.webgl')
var scene = new THREE.Scene()
var geometry = new THREE.BoxGeometry(1,1,1)
var material = new THREE.MeshBasicMaterial({ color: 0xff0000})
var mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
var sizes = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(600,800)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
window.addEventListener('dblclick', () =>
{
var fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement
if(!fullscreenElement)
{
if(canvas.requestFullscreen)
{
canvas.requestFullscreen()
}
else if(canvas.webkitRequestFullscreen)
{
canvas.webkitRequestFullscreen()
}
}
else
{
if(document.exitFullscreen)
{
document.exitFullscreen()
}
else if(document.webkitExitFullscreen)
{
document.webkitExitFullscreen()
}
}
})
var camera = new THREE.PerspectiveCamera( 75, sizes.width / sizes.height, 0.1, 100);
camera.position.z = 3;
scene.add(camera)
var controls = OrbitControls(camera, canvas)
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.render( scene, camera );
// document.body.appendChild( renderer.domElement );
// use ref as a mount point of the Three.js scene instead of the document.body
this.mount.appendChild( renderer.domElement );
// scene.add( mesh );
// var animate = function () {
// requestAnimationFrame( animate );
// };
// animate();
}
render() {
return (
<div ref={ref => (this.mount = ref)} />
)
}
}
const domNode = document.getElementById('root');
const root = createRoot(domNode);
root.render(<SimVis />);
// const rootElement = document.getElementById("root");
// ReactDOM.render(<SimVis />, rootElement);
// createRoot(<SimVis />, rootElement);
So the main things that are causing problems from what I can gather is that I don’t understand how to use useEffect() instead of componentDidMount() and I have no idea how this.mount.appendChild(…) is working. Please help