vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.62k stars 8.32k forks source link

inconsistent behaviour of watch and computed re-evaluation #9474

Closed plehnen closed 1 year ago

plehnen commented 1 year ago

Vue version

3.3.7

Link to minimal reproduction

https://play.vuejs.org/#eNq9U01v2zAM/SucLnZQN17SW5sE2IYetsM2bLtNOwgOY6uzZUMftgPD/32U3DjZVhQ99SaR71HvkdTA3jXNsnXIbtnGZFo2Fgxa1+y4klVTawsDaDwkkNVV4yzuE+iEzQoY4aDrCiLiRlxxldXKWKhMDltPiKOsECpHsIU00eKM6FcEOBWL4wVsdzBwBZ66bEXp8A7SFFTdBeoMBTprvEYPEf6OLeqjlRWGR6fXjC+kSb9WEPVRqCQtiLITR0/3CUN1EYwgYngOYmHAWC1V/oZ0jou7Wer6laT+JK2/Xi5WaC2Os9aTWucb6zv/9uzAeQdzLAwu7lcJXHhxq8nK1RUhQsFH2Ppv2PpfGFebdNoY2hW6WKyakuzSDWAjFbUC2uuq3mO55YyMczalCg3pdGp2rtkTBTppi8cZ3MIweC/juEn9Fv4HC+4n1PoC5eXMEljCrKEWHGS+fDC1ou0OLjjzM5Il6i+NldQizqiSz/icKMu6+xRiVjtMTvGswOz3E/EH0/sYZ181GtQtcjbnrNA52il9//0z9nSek9QUVxL6meQ3NHXpvMYJ9t6pPcm+wAW1H8Mfpbb9MPe9RWVOprxQjxwDnjP6ph+esX6We7O8CTyaMhv/AJChX6c=

Steps to reproduce

Create a watch of a computed, which is re-evaluated but its value hasn't changed.

What is expected?

The watch should not be triggered if the data has not changed.

What is actually happening?

If the return type is an array, the watch gets triggered anyways.

System Info

No response

Any additional comments?

My actual goal is to debounce a heavy calculation which currently gets triggered when anything in my array changes, even though it does not affect the calculation. At first I was expecting that a simple computed with a map of my relevant data would help, but even though the output of the computed does not change, the computed is marked as dirty as the dependency state is dirty. I understand that this is by design, but I am trying to find an easy solution to make a dependency only update on changes. I thought "watch" would be a good way, but as it seems it does not work as expected either, when the value is an array.

So I am mainly interested to find an easy/simple/intuitive solution to debounce my heavy calculation in a way, that it only gets re-calculated when the relevant data does really change.

i.e.

const suggestionPatterns = computed(() => (form.value?.groups?.map(g => g.pattern) ?? []));

watch(suggestionPatterns, () => {
    console.log('this gets called even if the patterns don't change, but some other property of form.value.groups change');
});

const suggestions = computed(() => {
  suggestionPatterns.value;
  console.log('this will be executed on all changes inside form.value, not only form.value.groups[].patterns');
});
plehnen commented 1 year ago

Is sort of related to #11399

jacekkarczmarczyk commented 1 year ago

Should be fixed by https://github.com/vuejs/core/pull/5912 And it's probably duplicate of some more issues in the repo

plehnen commented 1 year ago

Great, I hope that PR (from over a year ago) will get merged soon!

LinusBorg commented 1 year ago

The demonstrated behaviour is not inconsistent behaviour.

"x" === "x" // => true
["x"] === ["x"] // => false

The second computed returns a fresh array each time. So its value did change. So the watch callback gets called.

Great, I hope that PR (from over a year ago) will get merged soon!

That PR is still being worked on. It's a complex overhaul that needs extensive testing etc. But we want to merge it as soon as possible.