vue.jsvuejs2

VueJs, difference between computed property and watcher?


On Vue.js documentation there is an example like below:

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
    }
  }
})

The above code is imperative and repetitive. Compare it with a computed property version:

var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

What are the situations when watchers more suitable than computed properties? How should i decide which to choose? Documentation keeps saying it is more "generic" but does not really put its purpose.


Solution

  • Computed Properties

    A computed property sample:

    computed: {
       val () {
         return this.someDataProperty * someOtherVariable
       }
    }
    

    what does this particular piece of code do?

    1. It creates a property named val for the component (on the prototype so <vueInstanece>.hasOwnProperty('val') would show false).

    2. It has a dependency tree which consists of reactive properties (data properties, other computed properties) in this case : this.someDataProperty, which means the moment the dependencies change, the computed property will be recalculated.

    3. Although debated, can't have arguments passed to it. So something like

      computed: {
        val (flag) {
          return (flag === 1) 
            ? this.someDataProperty * someOtherVariable 
            : this.someDataProperty * 5
          }
      }
      

    can't be done

    [EDIT] See: https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter

    Watcher

    A watcher sample:

    watch: {
       val (n, o) {
         console.log(n, o)
       }
    }
    
    1. It does not create any new property, but it watches the changes over a reactive property.

    2. Watches only one specific property, unlike computed where any dependent property change can cause recalculation.

    3. Has arguments of new and old value.


    So computed properties would be the way to go if:

    You want a property that depends on other properties always. Like text formatting for a template, which is even the example in your code.

    Or reducing variable lengths as this is quite common:

    this.$store.state.someProperty.someNestedProperty.someDeeplyNestedProperty
    

    can be reduced to:

    computed: {
      someDeeplyNestedProperty () {
         return this.$store.state.someProperty.someNestedProperty.someDeeplyNestedProperty
      }
    }
    

    Not just reduction in variable size, each time the store updates, you will have the latest value in the someDeeplyNestedProperty.


    And Watchers are useful if you want to see if one reactive property has changed to a favourable value to know that you're ready to perform an action.

    like:

    watch: {
      somethingSelected() {
        this.router.push('someOtherRoute')
      }
    }
    

    EDIT: I came across some good article by Flavio Copes who listed common use cases for each of them (methods, computed props, watchers):

    When to use methods

    When to use computed properties

    When to use watchers