Skip to content

Watch runs unnecessarily when deep is true #13189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
elliotmoose opened this issue Apr 11, 2025 · 4 comments
Closed

Watch runs unnecessarily when deep is true #13189

elliotmoose opened this issue Apr 11, 2025 · 4 comments

Comments

@elliotmoose
Copy link

Vue version

3.5.12

Link to minimal reproduction

https://play.vuejs.org/#eNp9Uk2L2zAQ/SuDLk4gKOymvaTx0g/20B7a0paeBEWRJ7aysmT04QSM/3vHMtmkS9mT0Mx78948aWAfuo73CdmW7YLyuosQMKbuQVjdds5HGOAko2pghIN3LRQELt7ddD1KFXWP/wCEFdZgBLc/QvkMWQygrUW/JVrEc9xCcXe/KYg5LidGFlockiW0s4slwYQFosfk7TSLZzqfuGRhXMHC4um3NCtwpqJzCeUDDBNHORucQW5cvShiowOExiVTgXURfLKwRyVTwOwDKochd1QjbY3Fkqa/mNFLkwgkPUKQLW6LFczaUJblRT57GqBC7LYQfcIV6LbFSsuIc4E2pdnC7tZz2pQzXSK2nSEM3QB2+xSjs/BeGa2eSsEoiMtacE2Bch2Ac34tjBNiFCxPARiGF5HBmBG79SxAsN36RpmtWAy080HX/BicpS+RNQVTru20Qf+tm94lCEYPOGsIJo1xpy+5lhe+1FWD6uk/9WM4TzXBvnsM6HsU7LkXpa8xzu3Hn1/J8k2zdVUyhH6l+QPpvdLkcYZ9TLYi2ze47PZz/rra1r/C4zmiDZelJqM5w4wXjH7yp1dWv9rd8Ddz9nakFP/06KeZFOCGv+V392z8C08MImU=

Steps to reproduce

click the button

What is expected?

because the text doesn't change, I would expect it not to run

What is actually happening?

console.log triggers on every click, even though the text itself does not change

System Info

Any additional comments?

Why would I use deep for a string?

I stumbled upon this case when I was trying to watch a number of strings like so:

watch(() => [props.obj.id1, props.obj.id2], ..., { deep: true });

but it was running even though the ids had not changed. Turns out the watch source was being evaluated as a reactive effect. I suspect from here:

effect = new ReactiveEffect(getter)

@cv-r
Copy link

cv-r commented Apr 11, 2025

From the implementation perspective, this behavior is expected. When assigning a new value to a reactive reference, Vue internally uses Object.is to determine whether a change has occurred. In cases like = { ...inner }, a new object is created, which breaks the original reference. As a result, Vue treats it as a new value and proceeds with the corresponding reactivity updates.

1:The newly created object no longer maintains a reference relationship with the original one.

Image

2:The execution triggered the watch callback.

Image

3:Explanation of Object.is

Image

@elliotmoose
Copy link
Author

Yes, but I was surprised that 1. The behaviour differs with and without deep 2. That the callback gets triggered even though the old and new values are the same.

Maybe because I see some similarities to the angular paradigm, so I thought it would simply evaluate the return value as it is.

To be clear, I understand that the source function has to re-evaluate upon such an assignment. It's just strange that my callback gets triggered.

I also see the source method a bit like a memoization key, but perhaps that isn't the intention?

@skirtles-code
Copy link
Contributor

Is this the same as #11983?

@elliotmoose
Copy link
Author

Ah, it is the same, thanks for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants