Computed Vs Methods Vs Watch
Tags: vue
Published: 2021-01-17 04:34:53

Computed Properties allows you to define _auto calculated_ properties based on other properties. For example, you could have properties `firstName` and `lastName`, from which you could create a new property, `fullName`, which gets updated each time either `firstName` or `lastName` changes. For example,

```javascript
 data() {
    return {
      firstName: "",
      lastName: "",
    };
  },
  computed: {
    FullName: function() {
      return this.firstName.concat(this.lastName);
    },
  }
```

The `FullName` property would be recomputed each time `firstName` or `lastName` changes. You could now use the `FullName` property just as if you it was a normal property.

```html
<div>FirstName :{{ firstName }}</div>
<div>LastName :{{ lastName }}</div>
<div>FullName:{{ FullName }}</div>
```

**Computed Property Vs Method**

You would why a computed property and why not a method ? For example, you could achieve the above with following.

```javascript
GetFullName() {
      return this.firstName + " " + this.lastName;
    },
```

This could be consumed from your code as following

```html
<div>FirstName :{{ firstName }}</div>
<div>LastName :{{ lastName }}</div>
<div>FullName:{{ GetFullName() }}</div>
```

So what is the difference ? Well the difference lies in the fact that the _Computed Properties_ are cached internally, which the methods are recalculated each time, even if the corresponding property doesn't change.

For demonstration, let us add another property to our component, `age`.

```
export default {
  name: "Home",
  data() {
    return {
      firstName: "",
      lastName: "",
      age: 0,
    };
  },
}
```

The properties are bound to input boxes as the following.

```html
<div class="row">
  <div class="col-12 border py-3 bg-light">
    Inputs :
    <input v-model="firstName" placeholder="First Name" class="mx-2" />
    <input v-model="lastName" placeholder="Last Name" class="mx-2" />
    <input v-model="age" placeholder="Age" class="mx-2" />
  </div>
</div>
```

We will also define couple of _computed properties_ and _methods_ which would consumed in our code else where.

```javascript
  computed: {
    ComputedFullName: function() {
      console.log("Calling Computed Full Method");
      return this.firstName + " " + this.lastName;
    },
    ComputedAge: function() {
      console.log("Calling Computed Age Method");
      return this.age + "Yrs";
    },
  },
  methods: {
    GetFullName() {
      console.log("Calling FullName Method");
     return this.firstName + " " + this.lastName;
    },
    GetAge() {
      console.log("Call Age Method");
      return this.age + "Yrs";
    },
  },
```

As you could observe, we have declared two _computed properties_, namely, `ComputedFullName` and `ComputedAge`. We also have a corresponding pair of _methods_ namely `GetFullName` and `GetAge`.

We will use these properties and methods to display the values as following based on the input elements defined earlier.

```html
<div class="row g-2">
  <div class="col-4 border">
    <div><b>Computed</b></div>
    <div>FirstName :{{ firstName }}</div>
    <div>LastName :{{ lastName }}</div>
    <div>FullName:{{ ComputedFullName }}</div>
    <div>Age:{{ ComputedAge }}</div>
  </div>
  <div class="col-4 border">
    <div><b>Methods</b></div>
    <div>FirstName :{{ firstName }}</div>
    <div>LastName :{{ lastName }}</div>
    <div>FullName:{{ GetFullName() }}</div>
    <div>Age:{{ GetAge() }}</div>
  </div>
</div>
```

Let us now build and run our application and observe how it behaves.

Type a single character in the First Name input element and observe the console window.

```
Calling Computed Full Method
Calling FullName Method
Call Age Method
```

Since the `firstName` changes, the `ComputedFullName` property is called. So is the `GetFullName` method. These are pretty much desired and expected.

However, you could also observe that despite no changes to the `age` input element (and hence `age` property), the `GetAge()` method has been invoked. That is not the case with `ComputedAge` property. This is because, the Calculated property would be reevaulated only if the _reactive dependency_ changes. If the _reactive depencency_ does not change, the cached value is retrieved by the _computed property_, which reevaluting the property again.

On other hand, the method would be reevaluted each time it is invoked, irrespective of any changes to the dependend properties.

**Watched Properties**

If you want to your vue application to react to a change in a certain property, you have the option to use _Watch properties_.

But wait, does that sound similar to _computed property_. Yes and No - the watched properties observe a particular property in component and react (invokes a call back) to the change. This could be used to recalculate fields, which has same effect as the computed method. Since the watch is executed only when a property changes, it does share the issue of being reevaluated _unnecessarly_, as with methods.

For example, let us write the watch for `age` property.

```javascript
  data() {
    return {
      firstName: "",
      lastName: "",
      age: 0,
      ageString: "",
    };
  },
    watch: {
    age: function(value) {
      console.log("Watch Age : " + value);
      this.ageString = value + "Yrs";
    },
  },
```

The application would react to any changes to `age` property. In our call back in the given example, we are recalculating a property named `ageString` for each change in `age`. You might wonder how is it different from _computed property_ and when you would hesistate to use the _watch property_.

In fact, I should stop calling it watch property. Watch is a call back, a reaction to a change. This as such doesn't expose any property. You need to do that yourself. `Computed Property` in contrast is a property by definition and reacts to changes to the reactive dependencies. In the cases, it might be a good idea to use _computed property_. The reason is obvious if you were to complete the example by providing a watch to calculate the full name.

```javascript
data() {
    return {
      firstName: "",
      lastName: "",
      age: 0,
      fullName: "",
      ageString: "",
    };
  },
  watch: {
    firstName: function(value) {
      console.log("Watch FirstName : " + value);
      this.fullName = value + " " + this.lastName;
    },
    lastName: function(value) {
      console.log("Watch LastName : " + value);
      this.fullName = this.firstName + " " + value;
    },
    age: function(value) {
      console.log("Watch Age : " + value);
      this.ageString = value + "Yrs";
    },
  },
```

As you can observe, since a single `watch` would be observing a single property, you would need to define two watches to react to changes to both first name and last name. This would, as seen in the example above, result in duplicate code. This could be easily avoided by using `calculated properties.

As you would have observed, you could basically achieve the results with any of the above options. But the hidden implications are evident once your application grows and for the same reason, it is important to understand the subtle differences to ensure you use the right feature for your requirement.

Complete source code of the post could be accessed in my [Github](https://github.com/anuviswan/LearningPoint/tree/master/vuejs/V003/v003)