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

Unnecessary update of computed property and watcher call, triggered by update of dependent computed property, even when it is evaluated to the same primitive value #11884

Closed
marcel-dancak opened this issue Jan 22, 2021 · 3 comments

Comments

@marcel-dancak
Copy link

Version

2.6.11

Reproduction link

https://jsfiddle.net/marcel_dancak/xr2q40Lp/19/

Steps to reproduce

Open console output in demo example. Click on UPDATE button and watch log messages in console.

What is expected?

After each click on UPDATE button, computed property 'c' is updated, but it's value is still the same number value. Computed property 'params' doesn't need to be updated, because it depends only on property 'c', which always has the same primitive value. Watcher on property 'c' is not triggered, and I would expect watcher on 'params' property to be not triggered as well.

What is actually happening?

Computed property 'params' is updated on each click.


I understand why 'c' watcher function is not called, and why watcher function on computed property returning 'the same' complex object is called, but I didn't expect computed property with the same primitive value result to cause updates of other computed properties.

@sirlancelot
Copy link

sirlancelot commented Jan 22, 2021

In your example, params is not a primitive value. You've added a watcher for params, and since evaluation of this property returns a new object every time, you're going to see this. Vue doesn't do a deep check for equality in this way, you'll have to look in to a library like deep-equal to check for this condition.

I've actually ran in to this same issue and solved it similarly by watching a data property that gets updated through a secondary watcher. In the secondary watcher I compare the previous and current values for equality, and only update the data property when I've determined the values to be different.

Edit: Oh, I think I see where you're coming from now. Yes I agree that since c is the same primitive value, params shouldn't even need to be re-evaluated. Definitely a bug now IMO.

Edit 2: I also think there will be some amount of difficulty in fixing this though since computeds are queued for re-evaluation immediately (as in nextTick or setImmediate). So what you're doing in two statements - incrementing a by 1, and then decrementing b by 1 - actually is changing the value of c in between, resulting in params being queued for re-evaluation. I'm not sure the best way to fix this, but hopefully one of the owners can chime in.

@marcel-dancak
Copy link
Author

Yes, the main issue is update of params, which results in expected call of it's watcher. Shortly after submitting this issue I figured out that part about watcher in the title could be misleading.

This was just the very simple example to demonstrate, in real code I have computed property which parse single query string parameter and return primitive value. But because it depends on this.$route.query, it is evaluated on any change of query string, and triggers update of another computed property, even when it's not really changed. In this case I will probably simply use deep equal check function in watcher to prevent unnecessary fetching data with request.

Still it would be nice, if Vue would be able to prevent such unnecessary updates, where simple equality === check would be enough. I think that unnecessary updates can trigger unnecessary rendering, or it could cause performance issues, when you have heavy to compute properties. Finding workaround for this issues is possible, but additional code may be more difficult to follow or more prone to errors. However I understand there may be some internal challenges, and thus more difficult to implement as it seems.

@posva
Copy link
Member

posva commented Jan 23, 2021

This is expected, computed properties need to be reevaluated, c gets reevaluated with a and b changing and so does params because its dependency c depends on a and b and it needs to reevaluate and return a new object, triggering the watcher

@posva posva closed this as completed Jan 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants