I am facing an issue with my Thing
class. In the constructor, there is an asynchronous operation using fetch
. Once the fetch
completes, the result is assigned to a field in the Thing
object:
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)
}
}
The problem arises when I try to use thing.image
in a Vue
component. Vue does not detect the change in image
when the Promise resolves. This happens because in the constructor, this
refers to the raw Thing
and not Vue's reactive proxy wrapper. As a result, the assignment to this.image
bypasses the proxy.
Moving the load
call out of the constructor solves the reactivity issue as now this
inside the load
function refers to the reactive proxy. However, this makes it more complex to use the Thing
class.
I am looking for a better way to handle this particular issue. Can you help?
Here is a minimal example: (Vue playground link):
<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>