Deep watch always triggers when class setter is called, even if state does not change

I found that when deep watching an object of a class with a setter, the watch is triggered even if the object’s state does not change. In other words, calling the setter, even when setting the property to the current value, will trigger the watch handler function.

Here is a small example that shows how deep watch behaves differently for a simple object property and a class setter (you have to watch the console output).

Example on sfc.vuejs.org

Here is the code:

<template>
  <div @pointermove="onPointermove" style="height: 100vh; background: lightgray;" />
</template>


<script>  
  
class P {
  _x = 0;

  set x(x) {
    this._x = x;
  }
}
  

export default {
  name: "App",
  data() {return {
    p: new P(),
    q: {x: 0}    
  }},
  methods: {
    onPointermove() {
      this.p.x = 0;
      this.q.x = 0;
    }
  },  
  watch: {
  	p: {
      handler(pNew, pOld) {
        console.log('p', pNew, pOld);
      },
      deep: true  
		},
    q: {
      handler(qNew, qOld) {
        console.log('q', qNew, qOld);
      },
      deep: true  
		}
  } 
}    

</script>

There are two data objects. p has a setter for x, q is a simple object with an x property.

As you can see, the _x property of p and the x property of q will always be 0. But the watch on p is triggered every time the setter is called.

So my questions are:

  • Is this the intended behaviour of reactivity?
  • Is it mentioned in the documentation? I did not find anything, but then again I am good at overlooking things.
  • Is there another solution besides getting rid of the setter?