The Difference Between Computed Properties, Methods and Watchers in Vue

Share this article

The Difference Between Computed Properties, Methods and Watchers in Vue

Want to learn Vue.js from the ground up? Get an entire collection of Vue books covering fundamentals, projects, tips and tools & more with SitePoint Premium. Join now for just $14.99/month.

For those starting out learning Vue, there’s a bit of confusion over the difference between methods, computed properties and watchers.

Even though it’s often possible to use each of them to accomplish more or less the same thing, it’s important to know where each outshines the others.

In this quick tip, we’ll look at these three important aspects of a Vue application and their use cases. We’ll do this by building the same search component using each of these three approaches.

Methods

A method is more or less what you’d expect — a function that’s a property of an object. You use methods to react to events which happen in the DOM, or you can call them from elsewhere within your component — for example, from within a computed property or watcher. Methods are used to group common functionality — for example, to handle a form submission, or to build a reusable feature such as making an Ajax request.

You create a method in a Vue instance, inside the methods object:

new Vue({
  el: "#app",
  methods: {
    handleSubmit() {}
  }
})

And when you want to make use of it in your template, you do something like this:

<div id="app">
  <button @click="handleSubmit">
    Submit
  </button>
</div>

We use the v-on directive to attach the event handler to our DOM element, which can also be abbreviated to an @ sign.

The handleSubmit method will now get called each time the button is clicked. For instances when you want to pass an argument that will be needed in the body of the method, you can do this:

<div id="app">
  <button @click="handleSubmit(event)">
    Submit
  </button>
</div>

Here we’re passing an event object which, for example, would allow us to prevent the browser’s default action in the case of a form submission.

However, as we’re using a directive to attach the event, we can make use of a modifier to achieve the same thing more elegantly: @click.stop="handleSubmit".

Now let’s see an example of using a method to filter a list of data in an array.

In the demo, we want to render a list of data and a search box. The data rendered changes whenever a user enters a value in the search box. The template will look like this:

<div id="app">
  <h2>Language Search</h2>

  <div class="form-group">
    <input
      type="text"
      v-model="input"
      @keyup="handleSearch"
      placeholder="Enter language"
      class="form-control"
    />
  </div>

  <ul v-for="(item, index) in languages" class="list-group">
    <li class="list-group-item" :key="item">{{ item }}</li>
  </ul>
</div>

As you can see, we’re referencing a handleSearch method, which is called every time the user types something into our search field. We need to create the method and data:

new Vue({
  el: '#app',
  data() {
    return {
      input: '',
      languages: []
    }
  },
  methods: {
    handleSearch() {
      this.languages = [
        'JavaScript',
        'Ruby',
        'Scala',
        'Python',
        'Java',
        'Kotlin',
        'Elixir'
      ].filter(item => item.toLowerCase().includes(this.input.toLowerCase()))
    }
  },
  created() { this.handleSearch() }
})

The handleSearch method uses the value of the input field to update the items that are listed. One thing to note is that within the methods object, there’s no need to reference the method with this.handleSearch (as you’d have to do in React).

See the Pen Vue Methods by SitePoint (@SitePoint) on CodePen.

Computed Properties

While the search in the above example works as expected, a more elegant solution would be to use a computed property. Computed properties are very handy for composing new data from existing sources, and one of the big advantages they have over methods is that their output is cached. This means that if something independent of the computed property changes on the page and the UI is re-rendered, the cached result will be returned, and the computed property will not be re-calculated, sparing us a potentially expensive operation.

Computed properties enable us to make calculations on the fly using data that’s available to us. In this case, we have an array of items that need to be sorted. We want to do the sorting as the user enters a value in the input field.

Our template looks almost identical to the previous iteration, with the exception that we’re passing the v-for directive a computed property (filteredList):

<div id="app">
  <h2>Language Search</h2>

  <div class="form-group">
    <input
      type="text"
      v-model="input"
      placeholder="Enter language"
      class="form-control"
    />
  </div>

  <ul v-for="(item, index) in filteredList" class="list-group">
    <li class="list-group-item" :key="item">{{ item }}</li>
  </ul>
</div>

The script part is slightly different. We’re declaring the languages in the data property (previously this was an empty array) and instead of a method we’ve moved our logic into a computed property:

new Vue({
  el: "#app",
  data() {
    return {
      input: '',
      languages: [
        "JavaScript",
        "Ruby",
        "Scala",
        "Python",
        "Java",
        "Kotlin",
        "Elixir"
      ]
    }
  },
  computed: {
    filteredList() {
      return this.languages.filter((item) => {
        return item.toLowerCase().includes(this.input.toLowerCase())
      })
    }
  }
})

The filteredList computed property will contain an array of items that include the value of the input field. On first render (when the input field is empty), the whole array will be rendered. As the user enters a value into the field, filteredList will return an array that includes the value entered into the field.

When making use of computed properties, the data you want to compute has to be available, else this will result in an error in your application.

Computed property created a new filteredList property, which is why we can reference it in the template. The value of filteredList changes each time the dependencies do. The dependency that’s prone to change here is the value of input.

See the Pen Vue Computed Properties by SitePoint (@SitePoint) on CodePen.

Finally, note that computed properties let us create a variable to use in our template that’s built from one or more data properties. One common example is creating a fullName from the first and last name of a user like so:

computed: {
  fullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

In the template, you can then do {{ fullName }}. The value of fullName will change whenever the value of either the first or last name changes.

Watchers

Watchers are useful for cases when you want to perform an action in response to a change that has occurred (for example, to a prop or to a data property). As the Vue docs mention, this is most useful when you want to perform asynchronous or expensive operations in response to changing data.

In our search example, we can revert to our methods example and set up a watcher for the input data property. We can then react to any changes of value to input.

First, let’s revert the template to make use of the languages data property:

<div id="app">
  <h2>Language Search</h2>

  <div class="form-group">
    <input
      type="text"
      v-model="input"
      placeholder="Enter language"
      class="form-control"
    />
  </div>

  <ul v-for="(item, index) in languages" class="list-group">
    <li class="list-group-item" :key="item">{{ item }}</li>
  </ul>
</div>

Then our Vue instance will look like this:

new Vue({
  el: "#app",
  data() {
    return {
      input: '',
      languages: []
    }
  },
  watch: {
    input: {
      handler() {
        this.languages = [
          'JavaScript',
          'Ruby',
          'Scala',
          'Python',
          'Java',
          'Kotlin',
          'Elixir'
        ].filter(item => item.toLowerCase().includes(this.input.toLowerCase()))
      },
      immediate: true
    }
  }
})

Here, I’ve made the watcher an object (as opposed to a function). This is so that I can specify an immediate property, which will cause the watcher to trigger as soon as the component is mounted. This has the effect of populating the list. The function that’s run is then in the handler property.

See the Pen Vue Watchers by SitePoint (@SitePoint) on CodePen.

Conclusion

As they say, with great power comes great responsibility. Vue gives you the superpowers needed to build great applications. Knowing when to use each of them is the key to building what your users will love. Methods, computed properties and watchers are part of the superpowers available to you. Going forward, make sure to use them well!

Frequently Asked Questions (FAQs) about Computed Properties, Methods, and Watchers in Vue

What are the key differences between computed properties and methods in Vue?

Computed properties and methods in Vue both allow you to manipulate data. However, they function differently. Computed properties are cached based on their dependencies. This means that a computed property will only re-evaluate when some of its dependencies have changed. On the other hand, a method invocation will always run the function whenever a re-render happens. This makes computed properties more efficient when you need to perform expensive operations.

When should I use computed properties instead of methods?

Computed properties are ideal when you need to compute derived state based on store state. They are also useful when you want to listen to changes of one or more properties and compute a value from it. If the same result is needed in multiple places, a computed property can be more efficient and maintainable than a method.

Can computed properties depend on other computed properties?

Yes, computed properties can depend on other computed properties. Vue.js is smart enough to track dependencies and update the computed properties in the correct order.

How do watchers in Vue differ from computed properties?

Watchers are a more imperative way to react to data changes compared to computed properties. While computed properties declare a new reactive property based on other reactive properties, watchers allow you to perform arbitrary side-effects in response to a property’s change.

Can I use asynchronous operations inside computed properties?

No, computed properties in Vue.js are synchronous. If you need to fetch data or perform an asynchronous operation, consider using a method or a watcher instead.

How can I watch for changes in a computed property?

You can use a watcher to observe changes in a computed property. In the watcher function, you can perform any side-effect such as fetching data, validating input, or logging changes.

Can I use methods and computed properties together?

Yes, methods and computed properties can be used together in Vue. For example, you can use a method inside a computed property to perform a complex calculation.

How does Vue handle dependencies in computed properties?

Vue uses a dependency-tracking system to determine when to update computed properties. When a computed property is evaluated, Vue records all properties that were read as “dependencies”. Later, when a dependency changes, Vue knows which computed properties to re-evaluate.

Can I use computed properties in Vue templates?

Yes, computed properties can be used directly in Vue templates. They can be used just like normal properties, but they provide the added benefit of being cached and only updated when their dependencies change.

How can I debug computed properties in Vue?

You can use Vue’s devtools to inspect the dependencies of a computed property. This can help you understand why a computed property is updating or why it’s not updating when you expect it to.

Kingsley SilasKingsley Silas
View Author

Kingsley Silas is a web developer from Nigeria. He has a hunger for acquiring new knowledge in every aspect he finds interesting.

computed propertieslearn-vuemethodsvuevue-hubvue.jswatchers
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week