Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useLoader is throwing a Promise #3126

Closed
alankent opened this issue Dec 21, 2023 · 10 comments
Closed

useLoader is throwing a Promise #3126

alankent opened this issue Dec 21, 2023 · 10 comments

Comments

@alankent
Copy link

I have the following code in a largish application:

    try {
        gltf = useLoader(GLTFLoader, url)
    } catch(e) {
      console.error("WEIRD", e);
      e.then(x => {
        console.log(x);
      });
    }

The 'e' variable is a promise.

WEIRD Promise {<pending>}[[Prototype]]: Promise[[PromiseState]]: "fulfilled"[[PromiseResult]]: undefined
console.error @ client.js:2
window.console.error @ next-dev.js:27
overrideMethod @ console.js:213
myUseGLTF @ ThreeHelpers.js:70
eval @ TimelineMixer.js:86
Promise.then (async)
TimelineMixer @ TimelineMixer.js:79
DirectionsPage @ directions.js:552
renderWithHooks @ react-dom.development.js:16305
updateFunctionComponent @ react-dom.development.js:19583
beginWork @ react-dom.development.js:21596
beginWork$1 @ react-dom.development.js:27421
performUnitOfWork @ react-dom.development.js:26552
workLoopSync @ react-dom.development.js:26461
renderRootSync @ react-dom.development.js:26429
performConcurrentWorkOnRoot @ react-dom.development.js:25733
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
Show 14 more frames
Show less

undefined

So useLoader is throwing a promise, which .then() returns as undefined.
Is useLoader meant to throw a promise as an exception, or is there something going wrong here?
My overall app in this case is trying to load all the models to show on an animation timeline, including adding additional blend shapes to the models after loading. But I comment out all the other code, and I still get the above.

Thanks!

@CodyJasonBennett
Copy link
Member

This is an implementation detail of Suspense. If you want to catch or detect errors, use an error boundary.

@CodyJasonBennett CodyJasonBennett closed this as not planned Won't fix, can't repro, duplicate, stale Jan 7, 2024
@msub2
Copy link

msub2 commented Apr 4, 2024

Did you ever figure this out @alankent? Having a similar issue with useLoader + TextureLoader at the moment

@CodyJasonBennett
Copy link
Member

What is the issue exactly? Maybe see #3181 or #3181 (comment) specifically.

@msub2
Copy link

msub2 commented Apr 4, 2024

It may be worth a separate issue/discussion but essentially I'm trying to fetch an external image and apply that image as a texture to a plane. After some finagling I managed to get the actual error that's happening from THREE:

THREE.WebGLProgram: Shader Error 0 - VALIDATE_STATUS false

Material Name: 
Material Type: MeshBasicMaterial

Program Info Log: Must have a compiled vertex shader attached:
SHADER_INFO_LOG:
ERROR: 0:354: 'uvundefined' : undeclared identifier
ERROR: 0:354: 'constructor' : not enough data provided for construction
VERTEX

ERROR: 0:354: 'uvundefined' : undeclared identifier
ERROR: 0:354: 'constructor' : not enough data provided for construction

  349: void main() {
  350: #if defined( USE_UV ) || defined( USE_ANISOTROPY )
  351: 	vUv = vec3( uv, 1 ).xy;
  352: #endif
  353: #ifdef USE_MAP
> 354: 	vMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;
  355: #endif
  356: #ifdef USE_ALPHAMAP
  357: 	vAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;
  358: #endif
  359: #ifdef USE_LIGHTMAP
  360: 	vLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;

There's basically no useful info online about this but after checking on the three.js discord and checking three.js source I figured out that it seems to be a UV issue, specifically that the texture channel is undefined for some reason. Manually setting it to 0 prevents the error from happening but the once the material is set it just disappears instead of applying the texture correctly.

Abbreviated source:

export default function Banner(props) {
  useEffect(() => {
    // Once the async fetching of data is done bannerData is set
    if (bannerData) {
      const tex = new THREE.TextureLoader().load(bannerData.image);
      const material = new THREE.MeshBasicMaterial({ map: tex, transparent: true });
      setMaterial(material);
    }
  }, [bannerData]);

  const onClick = (event) => {
    // onclick handler, not relevant
  };

  return (
    <Suspense fallback={null}>
      <Interactive onSelect={onClick}>
        <mesh {...props} ref={mesh} scale={0.5} onClick={onClick} material={material}>
          <planeGeometry
            args={[formats[format].width * height, height]}
          />
          {/* <meshBasicMaterial map={texture} transparent={true} /> */}
        </mesh>
      </Interactive>
    </Suspense>
  );
}

@msub2
Copy link

msub2 commented Apr 4, 2024

I've found the root of my issue, after checking my example project lockfile I found it was relying on multiple different versions of three, so it was likely an API discrepancy. Deleting lockfiles and reinstalling so that only the latest three was depended on seems to have done the trick for me

@pranavmalikk
Copy link

pranavmalikk commented Apr 9, 2024

I've found the root of my issue, after checking my example project lockfile I found it was relying on multiple different versions of three, so it was likely an API discrepancy. Deleting lockfiles and reinstalling so that only the latest three was depended on seems to have done the trick for me

what version of three are you using across the board? It seems I get this issue as well, do i have to re-build one of my npm packages i'm using (realism-effects)? it only happens when i use ssgiEffects from this package

@msub2
Copy link

msub2 commented Apr 9, 2024

In my case the version I settled on was r162, though I believe the API discrepancy was introduced in r151, so I believe as long as you're not depending on versions both before and after this you'd be okay.

@pranavmalikk
Copy link

pranavmalikk commented Apr 9, 2024

In my case the version I settled on was r162, though I believe the API discrepancy was introduced in r151, so I believe as long as you're not depending on versions both before and after this you'd be okay.

unfortunately i spoke too soon, i'm still getting an error. Really flustered. Here is my code:

useFrame((state, delta) => {
gl.autoClear = true;
if (composerRef.current) {
composerRef.current.render(delta);
}
}, 1);

it states composerRef.current.render(delta); is giving me trouble. i'm using realism-effects and only happens when i do ssgiEffect. The HBAO, traa, and other effects have worked fine for me :(

@crispiestsquid
Copy link

I am having this issue as well right now. I am using the useLoader hook with the STLLoader.

"dependencies": {
    "@react-three/drei": "^9.105.6",
    "@react-three/fiber": "^8.16.6",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "three": "^0.164.1"
},
"devDependencies": {
    "@types/react": "^18.2.66",
    "@types/react-dom": "^18.2.22",
    "@types/three": "^0.164.0",
    "@typescript-eslint/eslint-plugin": "^7.2.0",
    "@typescript-eslint/parser": "^7.2.0",
    "@vitejs/plugin-react": "^4.2.1",
    "eslint": "^8.57.0",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.6",
    "typescript": "^5.2.2",
    "vite": "^5.2.0"
}

I found a code sandbox: https://codesandbox.io/p/sandbox/gifted-varahamihira-rrppl0y8l4?file=%2Fsrc%2FApp.js and I just modified it to include the useLoader hook and it seems to work fine.

The versions in that sandbox are:

@react-three/drei: 9.92.0
@react-three/fiber: 8.15.12
@types/three: 0.158.3
react: 18.2.0
react-dom: 18.2.0
react-scripts: 5.0.1
three: 0.159.0

I am going to try installing these exact versions locally and see if I have better luck. I feel like this is something worth digging into more since I just followed the getting started guide in the docs today and it is borked.

@crispiestsquid
Copy link

So actually, I found the solution and didn't need to change any package versions.

Turns out the problem was in the way my model component was setup. I was using state and useEffect to try loading the geometry from the url. For some reason that causes issues, my guess is with Suspense (I admittedly don't have a lot of experience with it).

Going from this:

function STLModel({ url }: STLModelProps) {
  const [geometry, setGeometry] = useState<BufferGeometry | null>(null)

  useEffect(() => {
    if (!url) return
    try {
      const geometry = useLoader(STLLoader, url)
      setGeometry(geometry)
    } catch (error) {
      if (error instanceof Error) {
        console.error('Error loading STL model:', error.message)
      } else if (error instanceof Promise) {
        error.then((err: unknown) => {
          console.error('Error loading STL model:', err)
        })
      } else {
        console.error('Error loading STL model:', error)
      }
    }
  }, [])

  return geometry ? (
    <mesh geometry={geometry}>
      <meshStandardMaterial color="orange" />
    </mesh>
  ) : null
}

to this:

function STLModel({ url }: STLModelProps) {
  let geometry: BufferGeometry | null = null
  geometry = useLoader(STLLoader, url)

  return geometry ? (
    <mesh geometry={geometry}>
      <meshStandardMaterial color="orange" />
    </mesh>
  ) : null
}

Not only does this solve the problem, but also simplifies the code a lot!

Maybe this will help someone else out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants