Creating reactive behavior with a Promise initiated within a constructor - A guide

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>

Answer №1

declare your class attribute as a reference

<script setup>
  import { reactive, ref } from 'vue'

  class Object {
    constructor() {
      this.image = ref(null)
      this.initialize()
    }

    async initialize() {
      const response = await fetch('https://placekitten.com/200/300')
      const blob = await response.blob()
      this.image.value = await createImageBitmap(blob)
    }
  }

  const item = reactive(new Object())
  // item.initialize() // This triggers reactivity as intended.
</script>

<template>
  <p v-if="item.image">
    Image dimensions are {{item.image.width}}×{{item.image.height}}
  </p>
  <p v-if="!item.image">
    Loading...
  </p>
</template>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The jQuery AJAX delete function is only able to capture the initial form submission

I am facing an issue with making an AJAX call to a PHP file to delete a row in the database. The problem is that it only deletes the first row. Despite my extensive research on this matter, I have not been able to find a solution. Therefore, I am reaching ...

A method for utilizing history.goBack in linked tabs while preventing the user from reverting to the previously selected tab

In my application, I have a settings modal that contains tabs which act as links to different paths. When the user clicks on the background outside of the modal, it triggers the history.goBack function. However, I noticed that if the user has already click ...

Continuously calling setState within the useEffect hooks causes an infinite loop

After extensive research and reading various articles on the topic, I am still facing the issue of infinite loops with useEffect and useState. One article that caught my attention was this one. Prior to reading the article, my useState function inside use ...

Error: Trying to assign a value to a null property

I am facing an issue while trying to dynamically create "iframe's textarea" and insert the value of a variable. Unfortunately, I keep encountering an error. Any suggestions on how to resolve this problem? P.S: Using Google Chrome as the browser ...

How to Display Custom Messages for Password Validation in Vuetify?

I currently have a password rule set up as follows: passwordRule(value){ const pattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})/; return ( pattern.test(value) || "Min. 8 charact ...

Obtain the position and text string of the highlighted text

I am currently involved in a project using angular 5. The user will be able to select (highlight) text within a specific container, and I am attempting to retrieve the position of the selected text as well as the actual string itself. I want to display a s ...

Are there any other options similar to PhantomJs that offer support for CSS 3D effects?

I am working on capturing a webpage using NodeJs. My current setup involves using PhantomJs to capture screenshots of the page and ffmpeg to convert them into videos. However, I have encountered an issue where the page contains 3D transform CSS, which is n ...

Evaluation of Google Closure Library's performance

When researching the performance of JavaScript libraries, I come across numerous websites that compare the speed of popular libraries including: jQuery (known for being slow) Prototype (especially sluggish in IE) Dojo (considered the fastest when it come ...

Tips for identifying the clicked location inside an element using JavaScript?

Is there a way in JavaScript to find out the exact position of a click within an element, like its distance from the left, right, or center? I'm struggling to determine whether the clicked area is on the left, center, or right side. https://i.stack.i ...

Save the output of a knex query to a variable

I'm struggling to assign the result of a select query using Knexjs to a variable. Here is my code: function getAllCategories() { let categories; categories = database.from("categories").select("category").then(function (rows) { for (let row of ro ...

Error: 'require' is not recognized as a valid command - Node.js

I recently attempted to integrate the d3-gauge plugin into a basic node.js/express server. Following the default directory structure generated by Express, I organized the files from the 'example' folder as follows: . ├── app.js ├── b ...

Executing code within Vue js $set method's callback

For my v-for loop that generates a list of flights, I have implemented functionality where the user can click on a "flight details" button to send an AJAX request to the server and append new information to the results array. To update the view accordingly ...

Could a potential concurrency issue arise when handling a Queue in JavaScript?

I am faced with a situation where I need to persist an array of properties via AJAX calls to a database. However, the current API does not allow sending the strings in batches, and simple looping will cause overwriting issues. To overcome this, I have impl ...

Incorporating additional rows into a SQL Table according to user-provided information

My application features editable table rows using Vue, which pull data from a database. Currently, there is a button (add line) that inserts a row into the database when clicked. Is it possible to automatically add a specified number of lines based on user ...

Switching from using jQuery.ajax() to fetch() when making requests to a Go REST API endpoint with no payload

I have a ReactJS web application that communicates with a REST API endpoint built in golang. Previously, I used jQuery to make Ajax POST requests and it worked perfectly. Here's an example of the code: // Using jQuery let sendUrl = "http://192.168.1 ...

How can I pass an object into EJS templates from views in Express 3.x?

Currently, I am utilizing ejs templates in combination with node.js and express 3.x. Is there a way to display the data object that is passed into the view? Can it be achieved similar to this example in index.ejs: <%= dump(session) %> ...

Tips for navigating libraries with Google CAJA

Is there a way to configure Google Caja to allow specific libraries to work without being sanitized? I have my own CAJA server and an application based on NodeJS. I'm providing users with code that is mostly related to charts and graphs, but certain ...

How can one effectively handle elements or objects that are both event listeners and event triggers?

Yesterday, I posted a similar question but found it too complex and vague after further research, so I removed it. I have now created a new demo here, which should be self-explanatory for the most part. Below are the HTML and JavaScript sections: <sel ...

Removing a selected row from a data table using an HTTP request in Angular 2

I am working with a table that has data retrieved from the server. I need to delete a row by selecting the checkboxes and then clicking the delete button to remove it. Here is the code snippet: ...

By utilizing jQuery, I am orchestrating the movement of a series of div elements within a container with the simple click of a button

A group of div elements located within a container. When the button is clicked, the train should start moving. <script> $('document').ready(function(){ $("button").click(function(){ $("#train").animate({left: "300px"}, 2000); ...