5

I'm trying to make a React component that renders a three.js scene. However, whenever I try mounting the component instead of seeing any sort of scene being rendered, I just see the text [object HTMLCanvasElement] being shown.

Here's my component:

import React from 'react';
import * as THREE from 'three';

class Cube extends React.Component {

    constructor() {
        super();
        this.animate = this.animate.bind(this);
        this.scene = new THREE.Scene();
        this.geometry = new THREE.BoxGeometry(200, 200, 200);
        this.material = new THREE.MeshBasicMaterial({
            color: 0xff0000,
            wireframe: true
        });
        this.mesh = new THREE.Mesh(this.geometry,this.material);
        this.scene.add(this.mesh);
        this.renderer = null;
        this.camera = null;
    }

    render() {
        if (typeof window !== 'undefined') {
            this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
            this.camera.position.z = 1000;
            this.renderer = new THREE.WebGLRenderer();
            this.renderer.setSize(window.innerWidth, window.innerHeight);
            return (
                <div dangerouslySetInnerHTML={{__html: this.renderer.domElement}}></div>
            );
        } else {
            return null;
        }
    }
}

export default Cube;

I got the code from the three npm package page and tried to convert it into a React component. What am I doing wrong that is making the scene not render?

1 Answer 1

4

In order to make it work you should do the following, keep ref to your container div element:

<div style={{width:"inherit", height:"inherit", position:"absolute"}} 
  ref={thisNode => this.container=thisNode}
>    
</div>  

This will keep your canvas inside. Next thing, in componentDidMount append your 3d canvas to container.

this.container.appendChild(renderer.domElement);

You also forget to call this.renderer.render(scene,camera); And also do not reinstantiate scene elements and renderer on every rerender. Think about this, if you will update scene with your current setup you will be recreating new scene, new renderer on every animation frame how is this could be even possible? Init your configurations in componentDidMount and then correct them in component didUpdate, also you can avoid bind by using arrow functions animate = () => {}.

Sign up to request clarification or add additional context in comments.

3 Comments

Isn't the whole point of react that you render things in the render() function. Is there no cleaner way to do this?
You are right, render, but not CREATE from scratch, this.renderer = new THREE.WebGLRenderer(); will create brand new webglrenderer, this is a big object which have attached scene and camera, in order to render what inside you should call METHOD of this object which is called render, and not recreating this huge object from scrach on each frame
also rendering threejs scene have nothing to do with rendering dom objects apart from connecting canvas to container in dom, what is drawn on your canvas determined by webglrenderer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.