Vue 3 — Computed Properties and Watchers
Tags: vue, webdev, programming, javascript
Published: 2021-01-25 23:37:54

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at Vue computed properties and watchers.

### Computed Properties

We can add computed properties to derive some from an existing property.

For instance, we can write:

```
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input v-model="message" />
      <p>{{reversedMessage}}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            message: ""
          };
        },
        computed: {
          reversedMessage() {
            return this.message
              .split("")
              .reverse()
              .join("");
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>
```

We added the `message` property to the object we return in `data` .

Then we added the `computed` property to the object we passed into `createApp` .

Methods are inside it getters, so we return things derived from other properties.

The method must be synchronous.

Now when we type in something to the input, we’ll see the reversed version displayed below it.

### Computed Caching vs Methods

We can achieve the same result by running a method to reverse the string.

But it wouldn’t be cached based on their dependency if we use a regular method to return derived data.

Computed properties are cached based on the original reactive dependencies.

As long as `this.message` stays the same, `reversedMessage` won’t be run.

However, if we have dependencies that aren’t reactive in our computed property, then the method won’t run.

In this case, we’ve to use methods to make them update.

So something like:

```
computed: {
  now() {
    return Date.now()
  }
}
```

won’t update.

### Computed Setter

We can have setters in our computed properties.

For instance, we can write:

```
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input v-model="firstName" placeholder="first name" />
      <input v-model="lastName" placeholder="last name" />
      <p>{{fullName}}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            firstName: "",
            lastName: ""
          };
        },
        computed: {
          fullName: {
            get() {
              return `${this.firstName} ${this.lastName}`;
            },
            set(newValue) {
              const names = newValue.split(" ");
              this.firstName = names[0];
              this.lastName = names[names.length - 1];
            }
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>
```

We have the `firstName` and `lastName` properties in the object we return with `data` .

Then we can create the getter for the `fullName` property by returning the 2 properties combined into one string.

The setter would be the `set` method which takes the `newValue` and then split it back into its parts.

We set the `this.firstName` and `this.lastName` based on the combined string we have returned from `get` .

When `this.firstName` and `this.lastName` change then `get` is run.

If `get` is run, then `set` is run.

### Watchers

Computed properties work for most cases, but sometimes we need watchers to provide us with a more generic way to watch for data changes.

For example, we can use it by writing:

```
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input v-model="name" />
      <p>{{data}}</p>
    </div>
    <script>
      const vm = Vue.createApp({
        data() {
          return {
            name: "",
            data: {}
          };
        },
        watch: {
          name(newName, oldName) {
            if (oldName !== newName) {
              this.getData(newName);
            }
          }
        },
        methods: {
          getData(newName) {
            fetch(`https://api.agify.io/?name=${newName}`)
              .then(res => res.json())
              .then(res => {
                this.data = res;
              });
          }
        }
      }).mount("#app");
    </script>
  </body>
</html>
```

We have a `getData` method which takes a `newName` parameter and get some data from an API.

And then we have our `watch` property, which has an object with watchers.

The name of the method would match the name of the instance property name.

A watcher takes an old value and a new value as the parameter.

And we can run what we want inside it.

The code we run is async so we got to use a watcher instead of computed properties.

### Conclusion

Computed properties and watchers let us watch for reactive data changes and let us run code when they change.