Reactjs Component

Hi everyone, I need help in converting class based component to functional component.
I have model with texture where the logic i have implemented is on click of button texture will be added to Model(glb). So far i have implemented using class based component in react but got confused like how i can have a same logic using functional component. I have checked for videos in youtube but it didnt work for me. Im looking for one similar example for reference so that i can go ahead implementing other models.
It could be a great help
Here is source code.

import React, { Component } from "react";
import * as BABYLON from "babylonjs";
import "babylonjs-loaders";

var scene;

class Mug extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.state = {
      height: window.innerHeight,
      width: window.innerWidth,
      useWireFrame: false,
      shouldAnimate: false,
    };
    this.updateDimensions = this.updateDimensions.bind(this);
  }

  componentDidMount = () => {
    // start ENGINE
    this.engine = new BABYLON.Engine(this.canvas, true);

    //Create Scene
    scene = new BABYLON.Scene(this.engine);
    scene.clearColor = new BABYLON.Color3(0.85, 0.85, 0.85);

    window.addEventListener("resize", this.updateDimensions);

    //Environment
    this.addEnv();

    //--Light---
    this.addLight();

    //--Camera---
    this.addCamera();

    //--Meshes---
    this.addModels();

    // Add Events
    window.addEventListener("resize", this.onWindowResize, false);

    // Render Loop
    this.engine.runRenderLoop(() => {
      scene.render();
    });

  };

  updateDimensions() {
    this.setState({
      height: window.innerHeight,
      width: window.innerWidth
    });
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions);
  };

  // componentWillUnmount() {
  //   window.removeEventListener("resize", this.onWindowResize, false);
  // }

  onWindowResize = event => {
    this.engine.resize();
  };

  // Environment texture
  addEnv = () => {
    var hdrTexture = new BABYLON.CubeTexture.CreateFromPrefilteredData("https://assets.babylonjs.com/environments/environmentSpecular.env", scene);
    hdrTexture.gammaSpace = false;
    scene.environmentTexture = hdrTexture;
  };

  /* Add Lights */
  addLight = () => {
    var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
    light.intensity = 0.7;
  };

  /* Add Camera */
  addCamera = () => {
    //camera pointing at your model.
    scene.createDefaultCameraOrLight(true, true, true);
    var camera = scene.getCameraByID("default camera");

    // To stop upper and lower roatation and rotate camera only left direction and right direction
    camera.upperBetaLimit = BABYLON.Tools.ToRadians(90)
    camera.lowerBetaLimit = BABYLON.Tools.ToRadians(90)

    camera.beta = 1.22;
    camera.alpha = 1.23;
    camera.radius = 0.25;
    camera.attachControl(this.canvas, true)

  };


  /*** Add Models */
  addModels = () => {
    this.materialedMeshes = [];
    BABYLON.SceneLoader.ImportMeshAsync("",
      "https://raw.githubusercontent.com/pavankulkarni11/3D_Meshes/main/",
      "mug_glb_itr4.glb", this.scene).then((frame) => {
        this.materialedMeshes.push(frame.meshes[1]); // push meshes that you want to give material (+texture) to array
      });
  };

  handleClick() {
    if (this.mat) { // if former material exist
      this.mat.dispose(); // free old material resources
    }
    this.mat = new BABYLON.StandardMaterial("mat", this.scene);
    this.mat.diffuseTexture = new BABYLON.Texture("https://devprojectupload.s3.ap-south-1.amazonaws.com/32490.png", this.scene);
    this.materialedMeshes.forEach(mesh => mesh.material = this.mat);
    this.mat.diffuseTexture.uAng = Math.PI;

  }


  render() {
    return (
      <>
        <canvas
          style={{ width: window.innerWidth, height: "550px" }}
          ref={canvas => {
            this.canvas = canvas;
          }}
        />
        <button className="btn btn-primary d-flex justify-content-center m-auto"
          onClick={this.handleClick}>
          Preview
        </button>
      </>
    );
  }
}
export default Mug;



You should take a look at the examples in Babylon.js and React | Babylon.js Documentation (babylonjs.com) and brianzinn/react-babylonjs: React for Babylon 3D engine (github.com) :smiley:

2 Likes

Okay Thank you so much for the reference @carolhmj

1 Like

Iā€™d be careful with the documentation example - it was updated in February and needs some community discussion based on a recent issue.

Main ideas can be summarized a bit like this:

import { useState, useEffect } from 'react';

const Mug = (props) => {

  const [state, setState] = useState({...}); // consider breaking apart state to separate variables

  // the fat arrow => is the bind(this)
  const handleClick = () => {
    // your logic here
  }

  useEffect(() => {
    // put your componentDidMount here
    return () => {
       //  this will run when your component unmounts
    }
  }, [] /* empty dependency array calls this just once */)

}
2 Likes

Thanks for letting me know @brianzinn. In most of cases i find examples using class based component and hardly find functional component for implementig babylon. And im totally new here so i always look for examples for reference. I try to use the format you have mentioned using hooks.

Hey @brianzinn, I need your guidance.
Am i doing it in right way?

import React, { useRef } from 'react';
import * as BABYLON from 'babylonjs';
import { Engine, Tools, Scene, ArcRotateCamera, HemisphericLight, Vector3, MeshBuilder, SceneLoader, CubeTexture,Texture, StandardMaterial } from '@babylonjs/core';
import { useEffect } from 'react';
import "babylonjs-loaders";


const mystyle = {
    width: '100%',
    height: '100%'
}

const ReactCanvas = props => {

    var canvasRef = useRef(null)

    // the fat arrow => is the bind(this)
    const handleClick = () => {
        if (mat) { // if former material exist
            mat.dispose(); // free old material resources
        }
       var mat = new StandardMaterial("mat", scene);
        mat.diffuseTexture = new Texture("https://devprojectupload.s3.ap-south-1.amazonaws.com/32490.png", scene);
        materialedMeshes.forEach(mesh => mesh.material = mat);
        mat.diffuseTexture.uAng = Math.PI;
    }

    useEffect(() => {
        const canvas = canvasRef.current
        const engine = new Engine(canvas, true);

        var createScene = function () {
            const scene = new Scene(engine);

            //Add lights
            var light = new HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
            light.intensity = 0.7;

            scene.createDefaultCameraOrLight(true, true, true);
            var camera = scene.getCameraByID("default camera");

            // To stop upper and lower roatation and rotate camera only left direction and right direction
            camera.upperBetaLimit = Tools.ToRadians(90)
            camera.lowerBetaLimit = Tools.ToRadians(90)

            camera.beta = 1.22;
            camera.alpha = 1.23;
            camera.radius = 0.25;
            camera.attachControl(canvas, true)


            // Add texture
            var hdrTexture = new BABYLON.CubeTexture.CreateFromPrefilteredData("https://assets.babylonjs.com/environments/environmentSpecular.env", scene);
            hdrTexture.gammaSpace = false;
            scene.environmentTexture = hdrTexture;

            // Add models
            SceneLoader.ImportMeshAsync("",
                "https://raw.githubusercontent.com/pavankulkarni11/3D_Meshes/main/",
                "mug_glb_itr4.glb", scene).then((frame) => {
                    materialedMeshes.push(frame.meshes[1]); // push meshes that you want to give material (+texture) to array
                });

            return scene;
        };

        const scene = createScene();

        engine.runRenderLoop(function () {
            scene.render();
        });

        window.addEventListener("resize", function () {
            engine.resize();
        });

    }, []);

    return (
        <>
            <canvas style={mystyle} ref={canvasRef} {...props}></canvas>
            <button onClick={handleClick}>Preview</button>
        </>
    )
}

export default ReactCanvas