Vue methods vs watchers vs computed properties

By

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.

Tagged: Vue.js · All topics

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

~~~

Related posts about vue: