vue calculation properties

Computing attributes

Expressions within templates are convenient, but they are actually only used for simple operations.Placing too much logic in a template can overweight and make it difficult to maintain.For example:

<div id="example">
  {{ message.split('').reverse().join('') }}
</div>

In this case, the template is no longer simple and clear.Before realizing that this is a reverse display of the message, you have to confirm it again.The problem gets worse when you want to reverse the message several times in the template

This is why computational attributes should be used for any complex logic

Basic examples

<div id="example">
    <p>Original message: "{{ message }}"</p>
    <p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
<script>
var vm = new Vue({
    el: '#example',
    data: {
        message: 'Hello'
    },
    computed: {    
        reversedMessage: function () {     // a computed getter
            return this.message.split('').reverse().join('')     // `this` points to the vm instance
        }
    }
})
</script>

Here we declare a computed property, reversedMessage.The function we provide will be used as a getter for the property vm.reversedMessage

console.log(vm.reversedMessage) // -> 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // -> 'eybdooG'

The value of vm.reversedMessage always depends on the value of vm.message.Therefore, when vm.message changes, all bindings that depend on vm.reversedMessage will also be updated.And best of all, we've created this dependency declaratively: getter s that compute attributes have no side effects, making it easy to test and infer

Compute Cache vs Methods

<p>Reversed message: "{{ reversedMessage() }}"</p>
<script>
methods: {     // in component
    reversedMessage: function () {
        return this.message.split('').reverse().join('')
    }
}
</script>

We can define the same function as a method instead of a calculated property.For the final result, the two approaches are indeed the same.However, the difference is that computed attributes are cached based on their dependencies.A computed property is reevaluated only if its dependent dependencies change.This means that as long as the message has not changed, multiple access to the reversedMessage calculation property immediately returns the previous calculation without having to execute the function again.

This also means that if reverseMessage is paid to a click event, in the computed method, multiple clicks transform the order only once.In contrast, whenever a re-rendering occurs, the method call always executes the function

Why do we need a cache?Suppose we have a computational attribute A with a high performance overhead that requires traversing a very large array and doing a lot of computations.Then we may have other computational properties that depend on A.If there is no cache, we will inevitably execute A getter more than once!If you don't want a cache, use method instead

Computed attribute vs Watched attribute

Vue does provide a more general way to observe and respond to data changes on Vue instances: the watch property.When you have some data that needs to change with other data, it's easy to abuse Watch - especially if you've used Angular JS before.However, it is generally better to use the computed attribute instead of the command watch callback.Think about this example:

<div id="demo">{{ fullName }}</div>
<script>
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
    }
  }
})
</script>

The above code is commandal and repetitive.Compare it to the version of the computed property:

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

Calculate setter

By default, a getter is the only computed property, but you can also provide a setter if you want:

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

Now when running vm.fullName ='John Doe', setter is called, and vm.firstName and vm.lastName are updated accordingly

Watchers

Although computational attributes are more appropriate in most cases, sometimes a custom watcher is also required.This is why Vue provides a more general way to respond to changes in data through the watch option.It is useful to perform asynchronous or expensive operations when you want to respond to data changes

<div id="watch-example">
    <p>Ask a yes/no question:
        <input v-model="question">
    </p>
    <p>{{ answer }}</p>
</div>
<script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://unpkg.com/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {    
    question: function (newQuestion) {   // If the question changes, the function will run
      this.answer = 'Waiting for you to stop typing...'
      this.getAnswer()
    }
  },
  methods: {    
    getAnswer: _.debounce(   // _.debounce is a function that limits the frequency of operations by lodash.In this example, we want to limit access to yesno.wtf/api.An ajax request will not be made until the user has finished typing
      function () {
        var vm = this
        if (this.question.indexOf('?') === -1) {
          vm.answer = 'Questions usually contain a question mark. ;-)'
          return
        }
        vm.answer = 'Thinking...'
        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
          })
      },

      500   // This is the number of milliseconds we waited for the user to stop typing
    )
  }
})
</script>

The use of the watch option allows us to perform asynchronous operations (access an API), limits how often we perform the operation, and sets the intermediate state before we get the final result.This is not possible with computed attributes.
In addition to the watch option, you can also use the vm.$watch API command

Keywords: Vue Attribute axios angular

Added by sugarat on Thu, 06 Jun 2019 19:06:20 +0300