If you're a Vue user, you likely know computed properties, and if you are like me, you probably think they are awesome - rightfully so!
To me, com...
For further actions, you may consider blocking this person and/or reporting abuse
My first thought was to put the expensive operation (reversing the list) in its own computed:
This way even though the
sortedList
computed property is updated often, it always uses the cachedreversedList
because Vue knows thatreversedList
only depends on the original list.Good idea, but in the example,
sortedList
was meant to be imagined as an expensive operation, mimicked by[...list]
that operation still happens each time the count is increased and is still <101.So this can be a way to work around the described problem in some scenarios but doesn't completely fit the imagined scenario here.
Hmm yeah, but if it's the sorting that's expensive then you could have a computed property for the sortedList instead. It's the same thing, the idea is to separate the expensive operation into its own computed property.
While you may be right here, I don't think this is supposed to be a perfect example.
Nice article and nice catch about the computed functions.
Thanks for thorough explanation on how computed props are excecuted and cached.
It's really usefull to bear that lazy nature of computed props in mind when you have lots of them and they depend on each other.
I spotted some mistakes though, which made it difficult to follow the article
According to the example, the
openTodos
relies ontodo.done
prop, and not justtodos.length
. Hence, the highlited statement is wrong.I believe you just forgot to update your example, becase in the end of the article there is another example where
openTodos
does depend ontodos.length
The example in the "When lazy evaluation can improve performance" section is outdated and is not the same as the one used in the Playground:
-- no "Toggle ListView" btn in the template
-- "hasOpenTodos" is not used in the template as well
-- "addTodo" function uses unknown "todo.value" vs "newTodo.value"
Please review the examples and the text
Thanks for the review. I fixed the example in your second point.
About the first point: It's not actually wrong in the place you thought, just an imrecise statement- the filter method would indeed not be run if the length of
todos
doesn't change - except if you would mutate the array with something like.reverse()
or.sort()
.But the example at the end of the article you refer to is indeed a copy-paste error from the initial example, so I fixed that to refer to
openTodos
.Thanks again
I tend to disagree :)
Reactive
todos
is deeply reactive, right?So if you change "done" prop of any of the todos, then the computed
openTodos
will need to be reevaluated and rerun the filter method even though the length stays the same.Argh. It's so hard to come up with good examples 😭
Yes you are right in this case - I wasn't really paying attention to what the filter did. 😬
Will see if I can change it to be more precise.
I actually encountered similar issue but arrived at a different solution:
Wrote a
useMemo
function that returns a wrapped reference that triggers downstream watcher only when some memorizationkey
from the original reference changed. Hence combining the best ofcomputed
andwatch
.Need to point out that there some difference in my requirement hence
eagerComputed
not suitable. In my caseeagerComputed
will fail.Excellent work!
Note: If you are using Vue 3.4+, you can straight use computed instead.
Because in Vue 3.4+, if computed new value does not change, computed, effect, watch, watchEffect, render dependencies will not be triggered.
refer: github.com/vuejs/core/pull/5912
This is an excellent article. I'm going from memory here but I could swear that some Vue components I've built in the past always seemed one tick behind where they were supposed to be.
I'm pretty sure that I've had to use watch() to fix the problem but I might also be conflating a slightly different issue with this.
Either way, this was really interesting and I'm glad that you took the time to write about it.
I switched from Vue to React within the past year or so for many of my personal projects and so I've been out of the loop a little bit, but I just took a job working with Vue. I feel like I've missed so much in the past few months. I was still using the options API with Vue 3 and without a setup directive and then I saw Vitesse.
Vue is such an awesome framework.
Glad you found it helpful.
the issue you describe sounds like it's not related to what I am describing here. Lazy evaluation won't cause any timing issues.
Also, don't feel pressures to use
setup()
if you feel comfortable with Options API - i won't disappear or anything.Hmm. I always assumed that since isOver100 would evaluate to false again, that sortedList would not see it as dirty because, although the computed ran again, it didn't change value, therefore sortedList would not have seen a change that would require a re-compute.
Also, this issue could be solved in a similar manner to Valentin Berlier's idea (other commenter), but slightly different:
Then in the template...
Right?
I can think of at least one more possible solution too, even closer to what Valentin stated, but in the end, that's not the point. Your point is to raise awareness of how this works so that we can be mindful and be able to fix/avoid it when we come across it.
An easy fix to this example situation would be to add a
key
on the button with the value ofcounter
Can you explain why adding a key solves the problem?
Vue uses keys for deterministic re-evaluation. It's use case is typically for loops, but a key can be used on any component/element. When a key changes, that forces Vue to do a re-evaluation.
Nope, additing key on the button would not make any difference
Hi, since you have a deep knowledge about computed property, could you write an article about using computed property with argument?
In my project, ive always encounter needing dynamic computed property especially when i want to use computed property in v-for loop where i need to get the index of the current item for the computed property. what i normally do is i created computed property that return a function that has one or more argument. ive read online this is not beneficial and the result are not being cached and the author suggest just to use normal function. so i would like to know is there any alternative to do this?
Dear Thorsten Lünborg,may I translate your article into Chinese?I would like to share it with more developers in China. I will give the original author and original source.
Not sure how using plain function solve the over100 example. If you replace the over100 computed with a plain function, sortedList will then be directly dependent on count.value so it will still be re-computed 100 times, no?
Wrote it in another comment:
It's so hard to come up with examples that are not about foo & bar and still demonstrate what you want to without being overly complex or missing the point 😅
Yes, a plain function would not help in that specific scenario. It can help in others.
I've already planned to revisit this article and add/change a few things to make my points more clear. For now, I added a note about this so people don't get a wrong impression.
What's your recommended approach to debug/detect the unnecessary render calls? Or track the "render queue" for lack of better term? :)