Loading blob file with react and get unexpected magic error

Hi guys. I am struck at importing blob files with react (I am still new to react).
I want to import glob files to model. but ends up with the magic error and no camera is defined,
Here is some of my code

....///some codes before
this.state = {
      blob: ""
    };
    this.onModelLoaded = this.onModelLoaded.bind(this);
  }
  onModelLoaded(e) {
    let file = e.target.files[0];
    var url = URL.createObjectURL(file);
    console.log(file.name);

    this.setState((state) => ({
      ...this.state,
      blob: url
    }));
    return url;

I assign the blob value into the rootURL within <Model/>

 <Suspense fallback={null}>
              <Model
                rootUrl={this.state.blob}
                sceneFilename=""
                pluginExtension=".glb"
              />
            </Suspense>

The entire code and the error can be seen in my codesandbox: babylonjs-react - CodeSandbox

@brianzinn is the daddy of this amazing framework :slight_smile:

hi @Kayla_Man
The reason is that you cannot load a model with an empty string. GLB files specifically start with a special “magic” identifier. This will get your scene loading:

{this.state.blob !== "" &&
  <Suspense fallback={null}>
    <Model
      rootUrl=""
      sceneFilename={this.state.blob}
      pluginExtension=".glb"
    />
  </Suspense>
}

Your code would be a cleaner with a Functional Component. I can show you how to switch it over, if you want - it looks like you got that started from an Storybook on the main repo.

1 Like

Hi brian, I would like to see how to do it with a functional component if you dont mind to show!

Thank you,
K

This is one way:
babylonjs-react (forked) - CodeSandbox

import React, { Suspense, useRef, useState } from "react";
import "@babylonjs/loaders";
import { Engine, Scene, Model } from "react-babylonjs";
import { Vector3, Tools } from "@babylonjs/core";

export default () => {
  const link = useRef();
  const [model, setModel] = useState({ url: "", extension: "" });

  function onFileInputChanged(e) {
    if (e.target.files.length > 0) {
      let file = e.target.files[0];
      var url = URL.createObjectURL(file);
      const extension = file.name.substring(file.name.lastIndexOf("."));
      console.log(`loading '${extension}'.`);
      setModel({ url, extension });
    }
  }

  return (
    <div onClick={() => link.current.click()}>
      <h2>Upload files here!</h2>
      <input
        style={{ display: "none" }}
        type="file"
        ref={link}
        onChange={onFileInputChanged}
      />
      <Engine antialias adaptToDeviceRatio canvasId="babylonJS">
        <Scene>
          <arcRotateCamera
            name="camera1"
            alpha={Tools.ToRadians(0)}
            beta={Tools.ToRadians(0)}
            radius={4}
            target={Vector3.Zero()}
            minZ={0.001}
          />
          <hemisphericLight
            name="light1"
            intensity={0.7}
            direction={Vector3.Up()}
          />
          {model.url !== "" && (
            <Suspense fallback={<box name="fallback" />}>
              <Model
                rootUrl=""
                sceneFilename={model.url}
                pluginExtension={model.extension}
              />
            </Suspense>
          )}
        </Scene>
      </Engine>
    </div>
  );
};

edit: that’s a more or less direct translation. just added extension otherwise state could be just a string.

1 Like

thank you!
i have another question but it isn’t related to the error or the component(they are all solved).
Is there any camera emb(similar to ArcRotateCamera) or command which can create camera similar to scene.createdefaultcamera in BabylonJS original library? I use but sometimes each object has different origin and it’s difficult to set the camera target.