Vue3 calculation properties

Posted by Kiubbo on Fri, 04 Mar 2022 13:22:51 +0100

Calculation attribute keyword: calculated.

Computational properties are useful when dealing with some complex logic.

Here is an example of an inverted string:

<title>Vue Test example - Rookie tutorial(runoob.com)</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
    {{ message.split('').reverse().join('') }}
</div>
    
<script>
const app = {
  data() {
    return {
      message: 'RUNOOB!!'
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>
</body>

In example 1, the template becomes very complex and difficult to understand.

The expressions in the template are very convenient, but they are designed for simple operations. Putting too much logic into the template will make the template too heavy and difficult to maintain. Therefore, for complex logic, vue advocates the use of computational attributes.

Next, let's take a look at an example using calculated attributes:

<title>Vue Test example - Rookie tutorial(runoob.com)</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
  <p>Original string: {{ message }}</p>
  <p>Invert string after calculation: {{ reversedMessage }}</p>
</div>
    
<script>
const app = {
  data() {
    return {
      message: 'RUNOOB!!'
    }
  },
  computed: {
    // Calculate the getter of the property
    reversedMessage: function () {
      // `this ` points to the vm instance
      return this.message.split('').reverse().join('')
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>
</body>

Instance 2 declares a calculation property reversedMessage.

The function provided will be used as the property VM getter of reversedmessage.

vm.reversedMessage depends on VM Message, in VM When message changes, VM The reversedmessage will also be updated.

computed vs methods

We can use methods instead of computed. The effect is the same for both, but computed is based on its dependency cache. It will be retrieved only when the related dependency changes. Using methods, when re rendering, the function will always be called and executed again.

<title>Vue Test example - Rookie tutorial(runoob.com)</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
  <p>Original string: {{ message }}</p>
  <p>use computed Invert string after calculation: {{ reversedMessage }}</p>
  <p>use methods Invert string after calculation: {{ reversedMessage2() }}</p>
</div>
    
<script>
const app = {
  data() {
    return {
      message: 'RUNOOB!!'
    }
  },
  computed: {
    // getter of calculated property
    reversedMessage: function () {
      // `this ` points to the vm instance
      return this.message.split('').reverse().join('')
    }
  },
  methods: {
    reversedMessage2: function () {
      return this.message.split('').reverse().join('')
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>
</body>

It can be said that using computed will have better performance, but if you don't want caching, you can use the methods attribute.

Theoretically, all implementations of computed can be completely replaced with methods.

<p>Reversed message: "{{ reversedMessage() }}"</p>
<p>Reversed message: "{{ reversedMessage }}"</p>
// Calculation properties
computed: {
  reversedMessage () {
    return this.message.split('').reverse().join('')
  }
}
// method
methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

Computed properties are cached based on their responsive dependencies. They are re evaluated only when the relevant responsive dependencies change. This means that the calculation of the message reverses function does not have to change as long as the calculation of the message reverses function is performed multiple times. And the method will execute.

Why do we need caching? Suppose we have A computing attribute A with high performance overhead, which needs to traverse A huge array and do A lot of calculations. Then we may have other computational properties that depend on A. If there is no cache, we will inevitably execute A's getter many times! If you don't want to have A cache, use method instead.

Similarities: computed and methods will be mixed into Vue instances. vm.reversedMessage/vm.reversedMessage() to obtain relevant calculation properties / methods.

computed setter

The computed property has only getter s by default, but you can also provide a setter when necessary:

<title>Vue Test example - Rookie tutorial(runoob.com)</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
 
</div>
    
<script>
const app = {
  data() {
    return {
      name: 'Google',
      url: 'http://www.google.com'
    }
  },
  computed: {
    site: {
      // getter
      get: function () {
        return this.name + ' ' + this.url
      },
      // setter
      set: function (newValue) {
        var names = newValue.split(' ')
        this.name = names[0]
        this.url = names[names.length - 1]
      }
    }
  }
}
vm = Vue.createApp(app).mount('#app')
document.write('name: ' + vm.name);
document.write('<br>');
document.write('url: ' + vm.url);
document.write('<br>------ Update data ------<br>');
// Call setter, VM Name and VM The URL will also be updated accordingly
vm.site = 'Rookie tutorial https://www.runoob.com';
document.write('name: ' + vm.name);
document.write('<br>');
document.write('url: ' + vm.url);
</script>
</body>

From the running results of the instance, it can be seen that the VM is running Site = 'rookie tutorial http://www.runoob.com '; When, the setter will be called, VM Name and VM The URL will also be updated accordingly.


In Vue, the attribute of computed can be regarded as data and can be read and set. Therefore, computed can be divided into getter and setter. Generally, there is no setter. Computed has only getter by default, that is, it can only be read and the setting value cannot be changed.

vue.js calculation attribute has only getter by default. Because it is the default value, we often omit it. The following code:

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

In fact, the complete code in calculated should be written as follows:

 computed: {
    fullName: {
      get(){
         return this.firstName + ' ' + this.lastName
      }
    }
  }

Calculate the trigger time of the property getter

<template>
    <div id="demo">
         <p> {{ fullName }} </p>
         <input type="text" v-model="firstName">
         <input type="text" v-model="lastName">
    </div>
</template>
 
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'zhang',
    lastName: 'san'
  },
  computed: {
    fullName: function () {
      console.log('computed getter...')
      return this.firstName + ' ' + this.lastName
    }
  },
  updated () {
     console.log('updated')
  }
})

If we change the values of firstName or lastName in the two input boxes in the above code, both calculated and updated () will be triggered, that is, console Log ('computed getter... ') and console Log ('updated ') (used to verify whether it has been executed, no other meaning)

It should be noted that it does not mean that if we change the variables used in the getter, the update of computed will be triggered. The premise is that the values in computed must be used in the template. How to understand?

In the following code, we comment out the fullName in the template:

<template>
    <div id="demo">
         <!-- <p> {{ fullName }} </p> -->
         <input type="text" v-model="firstName">
         <input type="text" v-model="lastName">
    </div>
</template>
 
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'zhang',
    lastName: 'san'
  },
  computed: {
    fullName: function () {
      console.log('computed getter...')
      return this.firstName + ' ' + this.lastName
    }
  },
  updated () {
     console.log('updated')
  }
})

Even if we change the firstName and lastName, the console in the getter in calculated will not be triggered Log ('computed getter... '), which will only trigger console log('updated')

Calculate property setter

<template>
    <div id="demo">
         <p> {{ fullName }} </p>
         <input type="text" v-model="fullName">
         <input type="text" v-model="firstName">
         <input type="text" v-model="lastName">
    </div>
</template>
 
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'zhang',
    lastName: 'san'
  },
  computed: {
    fullName: {
      //getter method
        get(){
            console.log('computed getter...')
            return this.firstName + ' ' + this.lastName
        },
   //setter method
        set(newValue){
            console.log('computed setter...')
            var names = newValue.split(' ')
            this.firstName = names[0]
            this.lastName = names[names.length - 1]
            return this.firstName + ' ' + this.lastName
        }
      
    }
  },
  updated () {
     console.log('updated')
  }
})

In the template, we can see that input is directly bound to v-model="fullName". If we directly modify the value of fullName here, setter, getter and updated functions will be triggered. The execution sequence is setter - > getter - > updated, as follows:

console.log('computed setter...')
console.log('computed getter...')
console.log('updated')

It should be noted here that getters are not triggered when setters are triggered. They are independent of each other. We modified fullName here to trigger getter because there is code in setter function to change the values of firstName and lastName. In other words, if we comment out the code of modifying firstName and lastName in the setter above, we will not execute getter, as follows:

set(newValue){
            console.log('computed setter...')
            // var names = newValue.split(' ')
           //  this.firstName = names[0]
          //  this.lastName = names[names.length - 1]
          return this.firstName + ' ' + this.lastName
        }

Will be executed in the following order, and

console.log('computed setter...')
console.log('updated')

Topics: Vue