Reactive Side-Effects with Vue 3 Watchers

Vue 3’s watch API lets you run arbitrary code whenever a reactive value changes. Its the reactive system’s hook for side-effects—loggging, validation, network requests, or synchronizing related state.

Listening to a single ref

<template>
  <p>Counter: {{ count }}</p>
  <button @click="count++">Increment</button>
</template>

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

const count = ref(1)

watch(count, (newVal, oldVal) => {
  alert(`Changed from ${oldVal} to ${newVal}`)
})
</script>

Two-way unit conversion

Below, two inputs stay synchronized by watching whichever field the user is editing.

<template>
  <label>
    Kilometers:
    <input v-model="km" @focus="active = 'km'" />
  </label>
  <br />
  <label>
    Meters:
    <input v-model="m" @focus="active = 'm'" />
  </label>
  <p id="log"></p>
</template>

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

const km = ref(0)
const m  = ref(0)
const active = ref('km')

watch(km, val => {
  if (active.value === 'km') m.value = val * 1000
})
watch(m, val => {
  if (active.value === 'm') km.value = val / 1000
})

watch(km, (newVal, oldVal) => {
  document.getElementById('log').textContent =
    `km changed from ${oldVal} to ${newVal}`
})
</script>

Triggering async work

The watcher below fires a GET request only when the question ends with a question mark.

<template>
  <p>
    <input v-model="query" placeholder="Ask something …" />
  </p>
  <p>{{ reply }}</p>
</template>

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

const query = ref('')
const reply = ref('Questions must end with ?')

watch(query, q => {
  if (!/[??]$/.test(q)) return

  reply.value = 'Thinking …'
  axios
    .get('/api/answer', { params: { q } })
    .then(res => (reply.value = res.data.answer))
    .catch(err => (reply.value = 'Error: ' + err.message))
})
</script>

Tags: vue3 WATCH Reactivity axios computed-effects

Posted on Wed, 03 Jun 2026 17:54:37 +0000 by pingu