Tengo una Thing de clase, cuyo constructor inicia una operación de fetch asincrónica. Cuando se completa la fetch , el resultado se asigna a un campo en el objeto Thing :
class Thing { constructor() { this.image = null this.load() } async load() { const response = await fetch('https://placekitten.com/200/300') const blob = await response.blob() this.image = await createImageBitmap(blob) } } Estoy usando thing.image en un componente Vue . El problema es que Vue no detecta el cambio en la image cuando se resuelve la Promise . Creo que entiendo por qué sucede esto: en el constructor, this se refiere a la Thing sin procesar, y no al contenedor de proxy reactivo de Vue. Entonces, la asignación a this.image termina sin pasar por el proxy.
Funciona si muevo la llamada de load fuera del constructor, de modo que this dentro de la función de load se refiera al proxy reactivo. Pero eso hace que mi clase Thing sea más difícil de usar.
¿Hay una mejor manera de manejar este problema?
Ejemplo mínimo ( enlace de Vue playground ):
<script setup> import { reactive } from 'vue' class Thing { constructor() { this.image = null this.load() // This does not trigger reactivity. } async load() { const response = await fetch('https://placekitten.com/200/300') const blob = await response.blob() this.image = await createImageBitmap(blob) } } const thing = reactive(new Thing()) // thing.load() // This triggers reactivity as expected. </script> <template> <p v-if="thing.image"> Image size is {{thing.image.width}}×{{thing.image.height}} </p> <p v-if="!thing.image"> Loading... </p> </template>define tu atributo de clase como una referencia
<script setup> import { reactive, ref } from 'vue' class Thing { constructor() { this.image = ref(null) this.load() } async load() { const response = await fetch('https://placekitten.com/200/300') const blob = await response.blob() this.image.value = await createImageBitmap(blob) } } const thing = reactive(new Thing()) // thing.load() // This triggers reactivity as expected. </script> <template> <p v-if="thing.image"> Image size is {{thing.image.width}}×{{thing.image.height}} </p> <p v-if="!thing.image"> Loading... </p> </template>