Skip to content
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

Deep watch on computed object does fire #10159

Closed
jonasnoki opened this issue Jan 19, 2024 · 3 comments
Closed

Deep watch on computed object does fire #10159

jonasnoki opened this issue Jan 19, 2024 · 3 comments

Comments

@jonasnoki
Copy link

Vue version

3.4.15

Link to minimal reproduction

https://play.vuejs.org/#eNqNU02P0zAQ/SuDL+1KbaJV4VK11QJaCTgAAgQXX7LJNHWJP2Q7baUo/52x3fQLWO0lSua9mffm2enYW2OyXYtszhautMJ4cOhbs+JKSKOthw4sriewL3y5mUCppWk9VtDD2moJI+odccVVqZXzoJ+2sISOM+lqzuYw+oBNo+GXtk31atQPNKFoyM+iaZHYNH58zbsLAwduUCTWIDwe38FyRRKKtDKSIew8LtuFZ2rVDWaNrsejCENEoNwUqkYXJCztaVWwzFUfJZOgsUKFDf/rLEZx9BFsJdEJpMqxPRWXZzx4nUAnpMRKFB7n4G3oqhDNPLwGD4s8HQLFTx8epWmISl8Ai839qutO7vp+kVMlIscFp1JX2Cw5O+fBWU6URX4xiU2Yd7TpWtTZ1mlFJ09hAnAWvIoG7RfjBSURzi8iASsohP2nWIu2h3q5wfL3P+pbdwg1zr5adGh35OSE+cLW6BP8+P0zHuj9BNIObUPsZ8BvSGfbBo+J9q5VFdm+4EW3H+P9Far+4R4PHpUblgpGA7OPfM7oCr9/ZvWz3Vk2i310XyjF9H9MZWFuckzA9RDSSGY33hs3z/OyUtRG5yV2NlPoc2Vk/kC03LbKC4nTSsuHWfY6u3+TV8L5y3qGTk6frN5TtDTlYvMwIOZtpxZVhTbk8jLdm7Yr7RvsL/1TLP0fy155kQ==

Steps to reproduce

Enter any input in the text field of the SFC playground.

What is expected?

Value of <h1> should be updated with value of text field.

What is actually happening?

The value does not get updated. The computed does get called as you can see when opening the console (the console log is printed). So the value of the computed is actually changed, but the watch is still not triggered.

System Info

No response

Any additional comments?

If you select any version prior to vue 3.4.0 the value of the <h1> is updated. What has changed?

@LinusBorg
Copy link
Member

This is a tricky edge case, I have a hard time rating this.

So, the cause is the change to computed() in 3.4: computed properties now only trigger dependent effects when their return value actually has changed.

The fact that previously, they always triggered dependent effects was a long-standing issue and often the cause of unexpected re-renders, leading to perf problems in various situations.

Your code took kind of advantage of this undesired behavior of computed():

  • Even though the return value of the computed()never changed (it's always the same object), it triggered the watcher's getter function.
  • Normally, the watcher callback would still not be executed because the value of the getter was also always the same object.
  • But by adding deep: true, that check is skipped, so both things combined cause the callback to be run.
  • However, this is not really a deep watch effect, as the object being watched is non-reactive, so its property changes are not observable

Now, in 3.4, the watch getter function won't be triggered by the computed as its return value didn't change. As explained, that is generally desired behavior, solving a bunch of problems for our users. So I don't think we want to bring back the old, undesired behavior of computed().

May I ask what the use case for this is in a real app?

@Doctor-wu
Copy link
Member

Like @LinusBorg said, computed would not re-calculate if the return value didn't change.
If you insist to use the computed like this which is hardly not suggested by official and you don't care about the performance, you can change the computed like this.

const comp = computed(() => {
obj.msg = inputValue.value
console.log('input value changes')
return {...obj}
})

@yyx990803
Copy link
Member

I would consider this expected behavior post 3.4, like @LinusBorg explained. In short: if a computed returns the same object, it will not trigger any changes.

This is the desired behavior for a more efficient system, and while the breakage is unfortunate, I think this might be better off in the long run that the new behavior is revealing problematic / incorrect usage of computed and force users to move away from such patterns.

In this case, the short-term workaround is shallow-cloning the object before returning it in the computed, like @Doctor-wu suggested. But for the long-term, you should try to find a better way to implement your desired functionality without relying on mutating other state in computed getters.

@yyx990803 yyx990803 closed this as not planned Won't fix, can't repro, duplicate, stale Jan 22, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Feb 6, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants