Vue Watchers

Watchersopen in new window are another way of reacting to a change to Vue data. They are functions, placed in the watch property of the Vue instance, the will be invoked when corresponding Vue data property has changed. Watchers are most useful when you need to perform asynchronous or expensive operations in response to changing data.

In the example below, the watcher is used to store the log to localStorage any time the log property has changed. This will insure that the latest log stays persistent.

const app = Vue.createApp({
  data: function () {
    return {
      log: '',
      input: ''
    }
  },
  mounted: function () {
    const log = localStorage.getItem('log')
    
    if (log) {
      console.log(log)
      this.log = log
    }
  },
  methods: {
    add: function () {
      this.log += "\n" + this.input
      this.input = ''
    }
  },
  watch: {
    log: function () {
      localStorage.setItem('log', this.log)
    }
  }
})

const vm = app.mount('#app')





















 
 
 
 
 



<div id="app" class="app">
  <textarea v-model="log"></textarea>
  <input @keyup.enter="add" type="text" v-model="input">
  <button @click="log=''">Clear Log</button>
</div>

By default, a watcher will not detect changes to a nested object. However, the setting the deep option to true will override the default tigger the watcher when changes are made to a nested object.

const counters = [
  { 
    title: 'Strikes',
    count: 0
  },
  {
    title: 'Balls',
    count: 0
  },
  {
    title: 'Outs',
    count: 0
  }
]

const app = Vue.createApp({
  data: function () {
    return {
      counters: counters
    }
  },
  created: function () {
    const counters = localStorage.getItem('counters')
    
    if (counters) {
      this.counters = JSON.parse(counters)
    }
  },
  watch: {
    counters: {
      deep: true,
      handler: function (counters) {
        localStorage.setItem('counters', JSON.stringify(counters))
      }
    }
  }
})

const vm = app.mount('#app')
<div id="app" class="counters">
  <div class="counter"
       v-for="counter in counters">
    <h1>{{ counter.count }}</h1>
    <h2>{{ counter.title }}</h2>
    <button @click="counter.count++">+</button>
    <button @click="counter.count = 0">&times;</button>
  </div>
</div>