My understanding of computed properties is that if the computed property is not used in the template it’s not supposed to be computed. However, when there is a watcher for a computed property, this computed property is evaluated.
I understand it’s not desired application architecture, but my question is if the fact that it’s working this way is a desired Vue behaviour or some side-effect of how things are implemented right now and can change in future releases?
Or to put the question in other words: Should the computed property be evaluated if it’s not used in the template and it has no other explicit getter in the codebase, except a watcher?
Example:
<template> <div> <button @click="counter++">+1</button> {{ counter }} </div> </template> <script> export default { name: "Main", data() { return { counter: 0, }; }, computed: { notUsedInTemplate() { console.log("notUsedInTemplate computed called"); return this.counter + 1; }, }, watch: { notUsedInTemplate() { console.log("notUsedInTemplate watch called"); }, }, }; </script>
Link to sandbox: https://codesandbox.io/s/computed-sandbox-ru3n3?file=/src/components/Main.vue:0-818
Advertisement
Answer
if the computed property is not used in the template it’s not supposed to be computed
…is not correct. Correct statement is:
if the computed property is not used (anywhere) it’s not supposed to be evaluated
Using watch
evaluates the property. In fact watch
is very similar to template re-rendering (In vue 3 re-rendering is in fact little special watchEffect)
Because to watch (anything):
- Vue 1st needs to run the code – in this case
notUsedInTemplate
getter – to find out what reactive data it is accessing (sothis.counter
is tracked as dependency) - When
this.counter
changes, watcher runs thenotUsedInTemplate
getter again so it can compare new value to previous one - If value changed, it runs the callback (which is logging in your example)
So to answer the questions:
- yes this is desired behavior as your watcher is not tracking changes of
notUsedInTemplate
computed property but underlying data it uses to compute it’s value - Watcher is accessing the computed property, there is no need to use it anywhere else
OK, more details WHY this works this way
Vue reactivity has always 2 phases:
- phase 1 – run the code (be it template or watch expression/fn) and collect all dependencies (e.g. any reactive data the code “touched”)
- phase 2 – track the dependencies. If any dependency changes, re-run callback (or render function)
See this chapter in the docs – How Changes Are Tracked – the example is explicitly mentioning only template re-rendering (which uses watcher created by Vue itself) but all of this applies to all watchers including those created by the user