Why Vue will update only once when two reactive data mutation super close?

Viewed 524

Please see this minimum example

export default {
  data() {
    return {
      name: "Amy",
      age: 18,
    };
  },
  computed: {
    combinedDataForWatching() {
      return {
        name: this.name,
        age: this.age,
      };
    },
  },
  watch: {
    combinedDataForWatching() {
      console.log("Triggered!");
    },
  },
  mounted() {
    setTimeout(() => {
      this.name = "Bob";
      this.age = 20;
    }, 1000);
  },
};

The console will only log "Triggered!" once, why is this happening?

And how does Vue determine this batch update?

2 Answers

From the Vue guide on reactivity:

In case you haven’t noticed yet, Vue performs DOM updates asynchronously. Whenever a data change is observed, it will open a queue and buffer all the data changes that happen in the same event loop. If the same watcher is triggered multiple times, it will be pushed into the queue only once. This buffered de-duplication is important in avoiding unnecessary calculations and DOM manipulations. Then, in the next event loop “tick”, Vue flushes the queue and performs the actual (already de-duped) work.

So both of those watch trigger updates occur in the same update cycle and are "de-duped" by the reactivity system into one call.

Based on @Dan's answer, we can wait for the next tick. In the Vue.js Composition API, this can fixed using nextTick provided by vue. Here is an example Vue.js SFC REPL that shows nextTick being used in action to call the watcher twice.

Related