This is the 12th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Two of the most important features in the Vue framework, computed and Watch, were similar before, so why do we have computed and Watch? And their usage scenarios? When to use computed? When to use watch? What’s the difference between them? Look at today’s article

Why is there a computed attribute computed

In Vue, it’s easy to map data to DOM, and it’s easy to use expressions in templates, but writing too much logic into templates can make them difficult to maintain.

<template>
  <div :title="msg">
    {{ msg }}
    {{ msg.length }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: 'Hello World',}}}</script>

Copy the code

For example, if we have a list of items, we can display different status information by the number of items, see the following example:

<template>
  <div class="status">{{ productList.length > 0 ? 'In stock' : 'Goods temporarily out of stock '}}</div>
</template>

<script>
export default {
  data() {
    return {
      productList: [{
        title: 'JS Advanced Programming ',}],}},}</script>
Copy the code

At this point, the template is no longer simple, and we have to look at the expression inside the template to know that its state depends on productList.length. If more than one place in the template needs the same state, we’ll have to write more than one copy of the same code, and the template will get worse.

So, when we need to deal with some complex logic of responsive data, we should use computed property computed. Look at the following example:

<template>
  <div class="status">
    {{ productStatus }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      productList: [{
        title: 'JS Advanced Programming ',}].}},computed: {
    productStatus() {
      return this.productList.length > 0 ? 'in stock' : 'Goods temporarily out of stock'}},}</script>
Copy the code

Here we declare a calculated property productStatus.

If we change the value of the productList array, we will see that productStatus is also modified accordingly.

We can bind computed properties to templates just as we bind normal properties. Vue internally knows that productStatus depends on productList, so when productList changes, all bindings that depend on productStatus are updated as well. The neat thing is that we’ve created this dependency declaratively, and the getters that calculate the properties have no side effects, making it easier to test.

Evaluate properties VS methods

The above code can also be implemented as a method, for example:

<template>
  <div class="status">
    {{ getProductStatus() }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      productList: [{
        title: 'JS Advanced Programming ',}].}},methods: {
    getProductStatus() {
      return this.productList.length > 0 ? 'in stock' : 'Goods temporarily out of stock'}},}</script>
Copy the code

We define the same logic as a function rather than evaluating properties. You can see that the results are exactly the same in both ways. So what’s the difference?

Here are the important ones. Please look carefully. The differences are:

Computed properties are cached based on response dependencies. Computed properties are reevaluated only when the response dependency changes. That is, if productList is never changed, each access to the productStatus computed property will return the previously computed result. You don’t have to execute the function again. In other words, the calculated property has the ability to cache data.

For example, the computed properties of the following code will never be updated because date.now () is not a reactive dependency:

computed: {
  now() {
    return Date.now()
  }
}
Copy the code

Instead of evaluating properties, methods are used in such a way that they are always executed again whenever a re-rendering is triggered. If there are N method calls in the template, it will be called N times.

So what are the advantages of a cache of computed attributes?

Let’s say we have a list of calculated attributes that are expensive in performance and need to iterate through a huge array and do a lot of calculations. And then we might have other computed properties that depend on the list. Without caching, we would inevitably execute the getter for list multiple times!

This will be much better in terms of performance.

Evaluate the Setter for the property

By default, we only have getters for computed properties, but we can also set a setter, as follows:

// ...
computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]}}}// ...
Copy the code

When we run this.fullName = ‘shuai’, the setter will be called and this.firstName and this.lastName will be updated accordingly.

This setter is something THAT I rarely use in my projects, so when will you use it? You’re welcome to provide the material.

Watch

Most of the time, calculating attributes can already satisfy our use, but Vue still provides us with a more free way to monitor data changes, that is watch.

So when do you use the watch?

As defined in the official Vue documentation

This approach is most useful when asynchronous or expensive operations need to be performed when data changes.

For an improved example, suppose we want to query a list of items by keyword

<div id="watch-example">
  <p>Please enter the name of the product<input v-model="keywords" />
  </p>
  <p v-if="getting">Data acquisition in..</p>
  <p v-else v-for="item in productList">{{ item.title }}</p>
</div>
Copy the code
<script>
  const watchExampleVM = Vue.createApp({
    data() {
      return {
        keywords: ' '.getting: false.productList: []}},watch: {
      // This function is triggered if the keywords change
      keywords(newKeywords, oldKeywords) {
        if (newKeywords.indexOf('? ') > -1) {
          this.getAnswer()
        }
      }
    },
    methods: {
      getProductList() {
        this.getting = true;
        axios
          .get('/api/products')
          .then(response= > {
            this.productList = response.data
          })
       		.finally(() = > {
          	this.getting = false;
        	})
      }
    }
  }).mount('#watch-example')
</script>
Copy the code

In this example, using Watch allows us to call asynchronous apis to retrieve data and control data state with getting attributes that we can’t do with computational attributes.

Abuse of the Watch

The Watch provided by Vue allows us to listen for any change in response data. When we have some data that needs to change with other data, it is easy to use Watch. However, it is better to use declarative calculation properties instead of the imperative Watch callback.

<div id="demo">{{ fullName }}</div>
Copy the code
const vm = Vue.createApp({
  data() {
    return {
      firstName: 'Foo'.lastName: 'Bar'.fullName: 'Foo Bar'}},watch: {
    firstName(val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName(val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
}).mount('#demo')
Copy the code

The code above is imperative and repetitive. Compare with the version of the calculated attribute:

const vm = Vue.createApp({
  data() {
    return {
      firstName: 'Foo'.lastName: 'Bar'}},computed: {
    fullName() {
      return this.firstName + ' ' + this.lastName
    }
  }
}).mount('#demo')
Copy the code

From the above comparison, it is much better to calculate attributes.

The last

Refer to the Vue official documentation: Calculate properties and listeners

Learn more front-end knowledge together, wechat search [Xiaoshuai’s programming notes], updated every day