Browse Source

fix: add initial value support to useLoader(#1007)

* fix: add initial value support to useLoader

- Enhanced the `useLoader` composable to accept an `initialValue` option, allowing users to provide a default state while resources are loading.
- Updated documentation to reflect the new `initialValue` feature, improving user experience by preventing null states during loading.
- Modified examples in the documentation and playground to demonstrate the usage of `initialValue` with textures and models.

* fix: update import order in use-loader documentation for consistency

- Adjusted the import order of `Texture` and `TextureLoader` from 'three' to maintain a consistent style across documentation examples.
- Minor formatting change in the example code for better readability.

* fix: ensure initialValue in useLoader defaults to null

- Updated the `useLoader` composable to default the `initialValue` option to `null` if not provided, enhancing robustness and preventing potential undefined states during loading.
- This change improves the composable's usability by ensuring a consistent default behavior.
Alvaro Saburido 1 week ago
parent
commit
be3280b011

+ 18 - 4
docs/composables/use-loader.md

@@ -24,9 +24,11 @@ You can also use the `useLoader` composable to load textures:
 
 ```ts
 import { useLoader } from '@tresjs/core'
-import { TextureLoader } from 'three'
+import { Texture, TextureLoader } from 'three'
 
-const { state: texture } = useLoader(TextureLoader, '/path/to/texture.jpg')
+const { state: texture } = useLoader(TextureLoader, '/path/to/texture.jpg', {
+  initialValue: new Texture(), // Provide an initial texture while loading
+})
 ```
 
 ## Features
@@ -36,6 +38,7 @@ const { state: texture } = useLoader(TextureLoader, '/path/to/texture.jpg')
 - 🧹 Automatic resource cleanup
 - 🔌 Extensible loader configuration
 - 🎮 Progress tracking support
+- 🎨 Initial value support for better UX
 
 ## API
 
@@ -58,6 +61,7 @@ const { state: texture } = useLoader(TextureLoader, '/path/to/texture.jpg')
 interface TresLoaderOptions<T extends TresObjectMap, Shallow extends boolean> {
   manager?: LoadingManager
   extensions?: (loader: TresLoader<T>) => void
+  initialValue?: T // Initial value to use while the resource is loading
   asyncOptions?: UseAsyncStateOptions<Shallow, any | null>
 }
 ```
@@ -95,7 +99,7 @@ const url = 'https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/bl
 
 ## Advanced Examples
 
-### Using a Loading Manager
+### Using a Loading Manager with Initial Value
 
 ```ts
 import { useLoader } from '@tresjs/core'
@@ -108,7 +112,9 @@ manager.onProgress = (url, loaded, total) => {
   console.log(`Loading file: ${url}. Loaded ${loaded} of ${total} files.`)
 }
 
-const { state } = useLoader<TresGLTF>(GLTFLoader, '/path/to/model.gltf', { manager })
+const { state } = useLoader<TresGLTF>(GLTFLoader, '/path/to/model.gltf', {
+  manager,
+})
 ```
 
 ### Loading Multiple Resources
@@ -180,3 +186,11 @@ const { load, state } = useLoader(GLTFLoader, '/initial-model.gltf')
 // Later in your code, load a different model
 load('/new-model.gltf')
 ```
+
+7. **Initial Values**: Provide initial values for better user experience while resources are loading (Useful to avoid having a null map and relying on v-if)
+```ts
+// For textures
+const { state: texture } = useLoader(TextureLoader, '/texture.jpg', {
+  initialValue: new Texture(), // Show a default texture while loading
+})
+```

+ 2 - 1
playground/vue/src/pages/loaders/texture-loader/TheExperience.vue

@@ -2,7 +2,7 @@
 /* eslint-disable no-console */
 import { OrbitControls } from '@tresjs/cientos'
 import { useLoader } from '@tresjs/core'
-import { LoadingManager, TextureLoader } from 'three'
+import { LoadingManager, Texture, TextureLoader } from 'three'
 
 const state = inject<{
   hasFinishLoading: boolean
@@ -20,6 +20,7 @@ const { state: texture, isLoading } = useLoader(
   'https://raw.githubusercontent.com/Tresjs/assets/main/textures/black-rock/Rock035_2K_Color.jpg',
   {
     manager,
+    initialValue: new Texture(),
   },
 )
 

+ 2 - 1
src/composables/useLoader/index.ts

@@ -28,6 +28,7 @@ export type LoaderProto<T> = new (manager?: LoadingManager) => TresLoader<T>
 export interface TresLoaderOptions<T, Shallow extends boolean> {
   manager?: LoadingManager
   extensions?: (loader: TresLoader<T>) => void
+  initialValue?: T
   asyncOptions?: UseAsyncStateOptions<Shallow, any | null>
 }
 
@@ -91,7 +92,7 @@ export function useLoader<T, Shallow extends boolean = false>(
         reject(err)
       })
     }),
-    null,
+    options?.initialValue ?? null,
     {
       ...options?.asyncOptions,
       immediate: options?.asyncOptions?.immediate ?? true,