Vue methods vs watchers vs computed properties

By

Tagged: Vue.js

Vue.js gives you methods, watchers, and computed properties. Learn when to use each one in Vue 3, from reacting to DOM events to deriving cached values.

In a Vue 3 component you have three places to put logic: methods, computed properties, and watchers. Use methods to react to events, computed properties to derive values from your data, and watchers to run side effects when a property changes.

They overlap a bit, so let’s look at each one with an example. The modern default is Composition API with <script setup>. Options API still works the same way if you prefer it.

When to use methods

A method is a function you call explicitly. Nothing runs until something calls it:

<script setup>
import { ref } from 'vue'

const count = ref(0)

function addOne() {
  count.value = count.value + 1
}
</script>

In the template you wire it to an event:

<button @click="addOne">Add one</button>

When to use computed properties

A computed property is a value derived from other values:

<script setup>
import { computed, ref } from 'vue'

const firstName = ref('Flavio')
const lastName = ref('Copes')

const fullName = computed(() => {
  return firstName.value + ' ' + lastName.value
})
</script>

In the template you use {{ fullName }} like any data property. Vue caches the result and only recomputes it when firstName or lastName change. A method called from the template runs again on every re-render instead. Details in Vue computed properties.

When to use watchers

A watcher runs a function every time one property changes. It’s the right tool for side effects, like a network request:

<script setup>
import { ref, watch } from 'vue'

const query = ref('')

watch(query, (newValue) => {
  fetch('/api/search?q=' + newValue)
})
</script>

More patterns (immediate, deep) live in Vue watchers.

The same with the Options API

If you use the Options API instead of <script setup>, the same ideas map to the methods, computed, and watch options. Mount the app with createApp, not new Vue:

import { createApp } from 'vue'

createApp({
  data() {
    return {
      count: 0,
      firstName: 'Flavio',
      lastName: 'Copes',
      query: ''
    }
  },
  methods: {
    addOne() {
      this.count = this.count + 1
    }
  },
  computed: {
    fullName() {
      return this.firstName + ' ' + this.lastName
    }
  },
  watch: {
    query(newValue) {
      fetch('/api/search?q=' + newValue)
    }
  }
}).mount('#app')

A common mistake

A computed property must return its value synchronously. If you put a fetch() call in a computed property, the template gets a Promise instead of the data you wanted.

When you need async work in response to a change, use a watcher. The watcher fires the request, and its callback stores the result in a data property the template can render.

Want me to talk about your product? You can sponsor this site.

Related posts about vue: