'Vue 3 setInterval Methods behavior

Env

I have a Vue 3 Application which requires a constant setInterval() to be running in the background (Game Loop).

I put that in store/index.js and call it from views/Playground.vue on mounted(). When leaving Playground i call beforeUnmount(). Making sure that not multiple setInterval() are running.

// store/index.js
startGameLoop({ commit, dispatch, getters }) {
  commit(
    "setIntervalId",
    setInterval(() => {
      dispatch("addPower", getters["ship/getFuelPerSecond"]);
    }, 1000)
  );
},

// Playground.vue
beforeUnmount() {
  clearInterval(this.intervalId);
}

In the top section of Playground.vue there is a score displayed and updated within the setInterval(). I use a library called gsap to make the changing numbers a bit pleasant for the eye.

<h2>Points: {{ tweened.toFixed(0) }}</h2>
watch: {
  points(n) {
    console.log("gsap");
    gsap.to(this, { duration: 0.2, tweened: Number(n) || 0 });
  },
},

Problem

methods from the Playground.vue are fired differently and i'm struggling to understand why that is the case.

gsap

the watch from the gsap is fired every second like i would expect from the setInterval() but...

Image

In the center of the Playground i display and image where the src part is v-bind to a method called getEnemyShipImage. In the future i would like to change the displayed enemie ship programmatically - but the method is called 34 times per second. Why is that?

<img
   :class="{ flashing: flash }"
   @click="fightEnemie()"
   :src="getEnemyShipImage()"
   alt=""
/>

getEnemyShipImage() {
   console.log("image");
   return require("@/assets/ships/ship-001.png");
}

Log (Browser)

Console Log Output



Solution 1:[1]

moved it to a part without using a method and switch changing images to a watch.

data: () => {
  return {
    ...
    selectedImages: "",
    images: [
      require("@/assets/ships/ship-001.png"),
      require("@/assets/ships/ship-002.png"),
      require("@/assets/ships/ship-003.png"),
    ],
  };
},

// initial value
mounted() {
  this.selectedImages =
    this.images[Math.floor(Math.random() * this.images.length)];
  this.$store.dispatch("startGameLoop");
}

// watch score
watch: {
    score() {
    this.selectedImages =
      this.images[Math.floor(Math.random() * this.images.length)];
  },
}

it's not perfect but better as initialy.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nick