Resize canvas in a React Component with useEffect

Hello!

I’m working on my very first project with Three.js, so I’m clearly just starting out. I’m also starting out with React.js, so maybe that’s where the problem lies, but I think it’s more to do with Three.js.

Here’s a simplified extract of my code (i just deleted some lights and meshs), note that the canvas is meant to be half of the size of the window :

const ThreeScene = ({cubes, aspectRatio}) => {
    const containerRef = useRef(null);
    const scene = new THREE.Scene();

    const createCube = (cube, scene) => {
        // code to add a cube to the scene
    }

    useEffect(() => {
        const camera = new THREE.PerspectiveCamera(70, (window.innerWidth / 2) / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth / 2, window.innerHeight);

        const container = containerRef.current;
        container.appendChild(renderer.domElement);

        // camera
        camera.position.z = 25;
        let controls = new OrbitControls(camera, renderer.domElement)
        controls.target.set(-10, 10, 10)

        // cube au centre de la scène à suppr après
        const newCube = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshPhongMaterial({color:0xff0000}))
        newCube.position.set(-10, 10, 10)
        scene.add(newCube)

        //light
        scene.add(new THREE.AmbientLight(0xffffff, .5))

        cubes.map((cube) => createCube(cube, scene))

        // Logique pour le rendu et la mise à jour

        const animate = () => {
            renderer.render(scene, camera);
            requestAnimationFrame(animate);
        };

        animate();

        return () => {
            container.removeChild(renderer.domElement)
        };
        
    }, [cubes, aspectRatio]);

    return <div ref={containerRef}></div>
}



export default ThreeScene

I’m having some problems with resizing the canvas while resizing the window.

My Three.js rendering is placed in a useEffect that depends on a “cubes” variable, which is an array of objects representing cubes and their coordinates. This means that the rendering is updated every time I add or delete a cube in the scene. The best solution I’ve found so far for managing resizing is to have a useState containing the window’s aspectRatio, updated each time the window is resized. I’ve added the aspectRatio to the useEffect’s dependencies, but here’s what it looks like:

When I resize the window, the canvas size isn’t updated at all, it’s supposed to be half the size of the window. No matter how I change the window size, it won’t change anything. But the moment I add or delete a cube, the resizing works.

initial situation : https://i.imgur.com/zsReOhG.png
resizing the window : https://i.imgur.com/EMDUQd3.png (see how the canvas goes over the grid)
after putting a cube : https://i.imgur.com/7WrcmTj.png (here the canvas is well resized)

It works as if the apectRatio dependency didn’t matter.

I tried something like this but it didn’t work any better: the rendering became black and empty when resizing.

function onWindowResize() {
    const newWidth = window.innerWidth / 2;
    const newHeight = window.innerHeight;

    renderer.setSize(newWidth / newHeight)
  
    camera.aspect = newWidth / newHeight
    camera.updateProjectionMatrix();
}

window.addEventListener("resize", onWindowResize, false)

I’ve been looking for a solution for a while now and I’m really counting on your help - thanks in advance!

This is because WebGLRenderer.setSize requires (width, height), not (width / height) as it is in the onWindowResize event handler:

renderer.setSize(newWidth / newHeight)
1 Like

ah thank you very much! I had seen this method many times and hadn’t noticed my mistake. Thanks for the help!

1 Like