Categories
Vue Tips

Vue Tips — Cleaning up Props, Computed Properties, and Watchers

Spread the love

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at ways to make developing Vue apps even easier, including reducing props accepted by components, and removing confusion between computed properties and watchers.

Cleaning up Props

We should reduce the number of props that a component takes. It takes components harder to work with and makes the code longer.

We can do this in several ways. The best way is to pass them in as the properties of objects of one prop instead of multiple props. For instance, we can write the following code to do that:

components/Button.vue :

<template>
  <button :style="styles">Button</button>
</template>

<script>
export default {
  name: "Button",
  props: {
    styles: Object
  }
};
</script>

App.vue :

<template>
  <div id="app">
    <Button :styles="{color: 'white', backgroundColor: 'black', outline: 'none'}"/>
  </div>
</template>

<script>
import Button from "./components/Button";

export default {
  name: "App",
  components: {
    Button
  }
};
</script>

In the code above, we passed in an object as the value of the style prop. It’s much more compact than passing in multiple props for each style.

Another example would be pass in multiple attributes with the v-bind directive:

components/Button.vue :

<template>
  <button v-bind="attrs">Button</button>
</template>

<script>
export default {
  name: "Button",
  props: {
    attrs: Object
  }
};
</script>

App.vue :

<template>
  <div id="app">
    <Button :attrs="{autofocus: 'true', name  : 'foo', type: 'button', value: 'foo'}"/>
  </div>
</template>

<script>
import Button from "./components/Button";

export default {
  name: "App",
  components: {
    Button
  }
};
</script>

In the code above, we pass in the attrs prop into the Button component, and then we used v-bind=”attrs” to apply them as attributes for out button element.

We should see the attributes applied when we inspect the button in the developer console.

Don’t Confuse Computed Properties and Watchers

Computed properties should be used as much as possible for derived properties unless we need to watch something and create side effects from them.

A computed property lets us derive new data from existing data. For instance, if we have firstName and lastName and we want to create a property fullName from firstName and lastName , we create a computed property as follows:

<template>
  <div id="app">{{fullName}}</div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      firstName: "Jane",
      lastName: "Smith"
    };
  },
  computed: {
    fullName() {
      return `${this.firstName} ${this.lastName}`;
    }
  }
};
</script>

In the code above, we have the computed property, which has the fullName method that returns `${this.firstName} ${this.lastName}` .

Then we reference it as a property like what we have in data in the template with {{fullName}} .

Computed properties are reactive. A new value will be returned if either firstName or lastName change. Therefore, it’ll always be up to date.

To do this with watchers, we have to write the following:

<template>
  <div id="app">{{fullName}}</div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      firstName: "Jane",
      lastName: "Smith",
      fullName: ""
    };
  },
  watch: {
    firstName: {
      immediate: true,
      handler() {
        this.fullName = `${this.firstName} ${this.lastName}`;
      }
    },
    lastName: {
      immediate: true,
      handler() {
        this.fullName = `${this.firstName} ${this.lastName}`;
      }
    }
  }
};
</script>

As we can see, the code above is much more complex, and we have to remember to set immediate to true , so that we can watch the initial value change in addition to the subsequent ones. In the handler functions, we have to set this.fullName each time.

It’s a much more complex and error-prone way to do the same thing as a computed property.

Computed properties are pure functions, whereas watcher handlers commit side effects, which also make them harder to test.

Where watchers are useful is for creating side effects. As we can see from the code above, it’s used for creating side effects by setting this.fullName as a combination of this.firstName and this.lastName .

For instance, we can use it as follows:

<template>
  <div id="app">
    <input v-model="name">
    <p>{{info.age}}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      name: "",
      info: {}
    };
  },
  watch: {
    async name(val) {
      const response = await fetch(`https://api.agify.io?name=${val}`);
      this.info = await response.json();
    }
  }
};
</script>

In the code above, we watch for the value of the name field and then calls the Agify API to get some data from the name.

Then we set the value of the response to this.info . We can’t do this with computed properties since we don’t want to return a promise in computed properties.

Conclusion

We should clean up our props by passing them in as objects instead of multiple props.

Computed properties are good for deriving data from existing data, while watchers are good for committing side effects like when we need to run asynchronous code.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *