VueJS $watch $refs

In mounted use code below:

this.$watch(
        () => {
            return this.$refs.<name>.<data>
        },
      (val) => {
        alert('$watch $refs.<name>.<data>: ' + val)
      }
    )

There is a work around to this. Consider that JavaScript doesn't create a copy of an array when assigning it to a variable, it merely creates a reference to the original array. Knowing that Vue's $refs are arrays, we can do the following:

<template>
    <div>
            <ul v-if="showAvailable">
                 <li v-for="pet in allPets.available" :key="pet.id" ref="pets">
                      {{ pet.name }}
                 </li>
            </ul>
            <ul v-else>
                 <li v-for="pet in allPets.unavailable" :key="pet.id" ref="pets">
                      {{ pet.name }}
                 </li>
            </ul>
    </div>
</template>

<script>

export default {
    props: ['allPets'],

    data() {
         showAvailable: true // Normally would change from a button or something
         shownPets: null // set to null for now
    },

    mounted() {
         this.$set(this.$data, 'shownPets', this.$refs.pets);    
    },

    watch: {
         shownPets: {
                         handler(newVal, oldVal){
                              // Do something when the DOM changes!
                         },
                         deep: true
                    }
    }
}
</script>

And voilà. We set our data shownPets to our pets $ref after the component mounts. The reference will hold different elements based on if showAvailable is true or false, and now we can watch for $ref or DOM changes.


No, $refs are not reactive, watch won't work.


You can $watch $refs.<name>.<data> but not $refs.<name> itself, not to mention $refs.

https://jsfiddle.net/kenberkeley/9pn1uqam/

const Counter = {
  data: () => ({
    i: 0
  }),
  template: `<fieldset>
    <p>Counter</p>
    <code>i = {{ i }}</code>
    <button @click="i += 1"> Add One </button>
  </fieldset>`
}

const App = {
  components: { Counter },
  mounted () {
    this.$watch(
        () => {
            return this.$refs.counter.i
        },
      (val) => {
        alert('App $watch $refs.counter.i: ' + val)
      }
    )
  },
  template: `<fieldset>
    <p>App</p>
    <counter ref="counter" />
  </fieldset>`
}

new Vue({
    el: '#app',
    render: h => h(App)
})