Skip to content

Commit

Permalink
feat(useLoader): support loader instances (#3131)
Browse files Browse the repository at this point in the history
  • Loading branch information
CodyJasonBennett authored Apr 26, 2024
1 parent 4c1242c commit 85fad8e
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 12 deletions.
38 changes: 26 additions & 12 deletions packages/fiber/src/core/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,27 @@ export type Extensions<T> = (loader: Loader<T>) => void

const memoizedLoaders = new WeakMap<LoaderProto<any>, Loader<any>>()

const isConstructor = <T,>(value: unknown): value is LoaderProto<T> =>
typeof value === 'function' && value?.prototype?.constructor === value

function loadingFn<T>(extensions?: Extensions<T>, onProgress?: (event: ProgressEvent) => void) {
return function (Proto: LoaderProto<T>, ...input: string[]) {
// Construct new loader and run extensions
let loader = memoizedLoaders.get(Proto)!
if (!loader) {
loader = new Proto()
memoizedLoaders.set(Proto, loader)
return async function (Proto: Loader<T> | LoaderProto<T>, ...input: string[]) {
let loader: Loader<any>

// Construct and cache loader if constructor was passed
if (isConstructor(Proto)) {
loader = memoizedLoaders.get(Proto)!
if (!loader) {
loader = new Proto()
memoizedLoaders.set(Proto, loader)
}
} else {
loader = Proto
}

// Apply loader extensions
if (extensions) extensions(loader)

// Go through the urls and load them
return Promise.all(
input.map(
Expand All @@ -128,14 +139,14 @@ type GLTFLike = { scene: THREE.Object3D }
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#useloader
*/
export function useLoader<T, U extends string | string[] | string[][]>(
Proto: LoaderProto<T>,
loader: Loader<T> | LoaderProto<T>,
input: U,
extensions?: Extensions<T>,
onProgress?: (event: ProgressEvent) => void,
) {
// Use suspense to load async assets
const keys = (Array.isArray(input) ? input : [input]) as string[]
const results = suspend(loadingFn(extensions, onProgress), [Proto, ...keys], { equal: is.equ })
const results = suspend(loadingFn(extensions, onProgress), [loader, ...keys], { equal: is.equ })
// Return the object(s)
return (Array.isArray(input) ? results : results[0]) as unknown as U extends any[]
? LoaderResult<T>[]
Expand All @@ -146,18 +157,21 @@ export function useLoader<T, U extends string | string[] | string[][]>(
* Preloads an asset into cache as a side-effect.
*/
useLoader.preload = function <T, U extends string | string[] | string[][]>(
Proto: LoaderProto<T>,
loader: Loader<T> | LoaderProto<T>,
input: U,
extensions?: Extensions<T>,
): void {
const keys = (Array.isArray(input) ? input : [input]) as string[]
return preload(loadingFn(extensions), [Proto, ...keys])
return preload(loadingFn(extensions), [loader, ...keys])
}

/**
* Removes a loaded asset from cache.
*/
useLoader.clear = function <T, U extends string | string[] | string[][]>(Proto: LoaderProto<T>, input: U): void {
useLoader.clear = function <T, U extends string | string[] | string[][]>(
loader: Loader<T> | LoaderProto<T>,
input: U,
): void {
const keys = (Array.isArray(input) ? input : [input]) as string[]
return clear([Proto, ...keys])
return clear([loader, ...keys])
}
18 changes: 18 additions & 0 deletions packages/fiber/tests/hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,24 @@ describe('hooks', () => {
expect(extensions).toBeCalledTimes(1)
})

it('can handle useLoader with an existing loader instance', async () => {
class Loader extends THREE.Loader {
load(_url: string, onLoad: (result: null) => void): void {
onLoad(null)
}
}

const loader = new Loader()
let proto!: Loader

function Test(): null {
return useLoader(loader, '', (loader) => (proto = loader))
}
await act(async () => root.render(<Test />))

expect(proto).toBe(loader)
})

it('can handle useLoader with a loader extension', async () => {
class Loader extends THREE.Loader {
load(_url: string, onLoad: (result: null) => void): void {
Expand Down

0 comments on commit 85fad8e

Please sign in to comment.