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

fix(useLoader): loosen GLTF inference check #3105

Merged
merged 3 commits into from
Dec 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions packages/fiber/src/core/hooks.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as THREE from 'three'
import * as React from 'react'
import { StateSelector, EqualityChecker } from 'zustand'
import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { suspend, preload, clear } from 'suspend-react'
import { context, RootState, RenderCallback } from './store'
import { buildGraph, ObjectMap, is, useMutableCallback, useIsomorphicLayoutEffect } from './utils'
Expand Down Expand Up @@ -114,6 +113,8 @@ function loadingFn<L extends LoaderProto<any>>(
}
}

type GLTFLike = { scene: THREE.Object3D }

/**
* Synchronously loads and caches assets with a three loader.
*
Expand All @@ -125,14 +126,14 @@ export function useLoader<T, U extends string | string[], L extends LoaderProto<
input: U,
extensions?: Extensions<L>,
onProgress?: (event: ProgressEvent<EventTarget>) => void,
): U extends any[] ? BranchingReturn<R, GLTF, GLTF & ObjectMap>[] : BranchingReturn<R, GLTF, GLTF & ObjectMap> {
): U extends any[] ? BranchingReturn<R, GLTFLike, R & ObjectMap>[] : BranchingReturn<R, GLTFLike, R & ObjectMap> {
// Use suspense to load async assets
const keys = (Array.isArray(input) ? input : [input]) as string[]
const results = suspend(loadingFn<L>(extensions, onProgress), [Proto, ...keys], { equal: is.equ })
// Return the object/s
return (Array.isArray(input) ? results : results[0]) as U extends any[]
? BranchingReturn<R, GLTF, GLTF & ObjectMap>[]
: BranchingReturn<R, GLTF, GLTF & ObjectMap>
? BranchingReturn<R, GLTFLike, R & ObjectMap>[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any tests asserting the type output? Would like to see an output where we're not relying on type augmentation to access nodes / materials / etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to test with TS 4 and 5 since #2723 (comment).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like he shouldn't be declaring the generic?

Copy link
Member Author

@CodyJasonBennett CodyJasonBennett Nov 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like he shouldn't be declaring the generic?

Probably, but I'll do integration tests to make sure this will "just work" when we release in R3F. It's possible we need to regenerate types in Drei.

Do we have any tests asserting the type output? Would like to see an output where we're not relying on type augmentation to access nodes / materials / etc.

Done in 803ee2c.

: BranchingReturn<R, GLTFLike, R & ObjectMap>
}

/**
Expand Down
12 changes: 9 additions & 3 deletions packages/fiber/tests/core/hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,23 @@ describe('hooks', () => {
})

it('can handle useLoader hook', async () => {
let gltf!: Stdlib.GLTF & ObjectMap

const MockMesh = new THREE.Mesh()
MockMesh.name = 'Scene'

jest.spyOn(Stdlib, 'GLTFLoader').mockImplementation(
() =>
({
load: jest.fn().mockImplementation((_url, onLoad) => {
onLoad(MockMesh)
onLoad({ scene: MockMesh })
}),
} as unknown as Stdlib.GLTFLoader),
)

const Component = () => {
const model = useLoader(Stdlib.GLTFLoader, '/suzanne.glb')
return <primitive object={model} />
gltf = useLoader(Stdlib.GLTFLoader, '/suzanne.glb')
return <primitive object={gltf.scene} />
}

let scene: THREE.Scene = null!
Expand All @@ -122,6 +126,8 @@ describe('hooks', () => {
await waitFor(() => expect(scene.children[0]).toBeDefined())

expect(scene.children[0]).toBe(MockMesh)
expect(gltf.scene).toBe(MockMesh)
expect(gltf.nodes.Scene).toBe(MockMesh)
})

it('can handle useLoader hook with an array of strings', async () => {
Expand Down