Vue.js Computed Properties and Watchers: Managing Complex Logic
In-template expressions are convenient only for simple operations. When we put too much logic in our templates, they become bloated and thus hard to maintain:
<span id=?app?>
{{information.split(??).reverse().join(??)}}
</span>
In the example above, the template is no longer declarative and simple. One has to take a second look to realize that it displays the information in reverse. This becomes worse when we need to include the reversed message in our template more than once.
Thus for any complex logic, use computed property.
Basic Example
HTML
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
JS
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
})
Much as you would expect, the snippet above respectively displays:
Hello olleH
the value of reversedMessage is always dependent on the message property, hence vm.reversedMessage always changes with changes to vm.message.
Computed Caching vs Method
HTML:
<p>Reversed message: "{{ reverseMessage() }}"</p>
JS:
// in component
methods: {
reverseMessage: function () {
return this.message.split('').reverse().join('')
}
}
As shown in the snippet above, it is possible to a method to achieve the same result as a computed property. Both have the same result as seen. But computed properties are cached based on their reactive dependencies. A computed property will re-evaluate only when some of its reactive dependencies change, thus multiple access to the reversedMessage will return the previously computed result without running the function again. In contrast a method invocation will always run whenever a re-render occurs.
Caching is necessary whenever we don?t want to executes a property?s getter more than necessary, else use method instead.
Computed vs Watched Property
Vue provides a watch property which is a more generic way to observe and react to data changes on the Vue instance. It is however a good idea to always use computed property as against watch when you have some data that needs to change based on some other data. An example is as shown:
HTML
<div id="demo">{{ fullName }}</div>
JS
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
Below is a computed property version of the code above:
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
Computed Setter
The computed properties are by default getter-only, however you can provide a setter when needed:
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
//
Running vm.fullName = ?Aryan Yuksek?, the setter will be invoked and vm.lastName vm.lastName updated accordingly.
Watchers
Though computed properties are more appropriate in most cases, custom watcher is however necessary in certain times. This is the reason Vue provides us with th e watch option. The watch option especially useful when we want to perform async operations. For example:
<div id="watch-example">
<p>Ask a yes/no question: <input v-model="question"></p>
<p>{{ answer }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
<script>
var watchExampleVM =new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'You have to ask a question, for me to give you an answer'
},
watch: {
question: function (newQuestion,oldQuestion) {
this.answer ='Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods:{
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API.'+ error
})
}
}
})
</script>
As can be seen, the watch option allows us to perform an async operation, limit how often we perform the operation, and set intermediary states until we get final answer.
Previous:
Vue.js Template Syntax: Interpolations, Directives, and Data Binding.
Next:
Vue.js Class and Style Bindings: Dynamically Manage CSS.
It will be nice if you may share this link in any developer community or anywhere else, from where other developers may find this content. Thanks.
https://www.w3resource.com/vue/computed-properties-and-watchers.php
- Weekly Trends and Language Statistics
- Weekly Trends and Language Statistics