Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue: Do watchers on deep nested objects log oldVal and newVal?

Tags:

vue.js

vuejs2

I have a watcher on a deep nested object. I am using Vue.set() to add a reactive property to the object. This is triggering the watcher but the both the newVal and oldVal console logs are showing the data with the new property added to it already rather than the oldVal showing what it was prior to adding the new property to it.

  <button @click="addData">Add</button>


  data() {
    return {
      myData: {
        time: {

        }
      }
    }
  },
  watch: {
    myData: {
      handler(newVal, oldVal) {
        console.log("NEW", newVal);
        console.log("OLD", oldVal);
      },
      deep: true
    }
  },
  methods: {
    addData() {
      this.$set(this.myData.time, 'other','testing')
    }
  }
like image 957
MauirceA Avatar asked Sep 11 '25 16:09

MauirceA


1 Answers

As mentioned by @Terry, vue doesnt keep a referency to the oldValue, see what the docs says:

Note: when mutating (rather than replacing) an Object or an Array, the old value will be the same as new value because they reference the same Object/Array. Vue doesn’t keep a copy of the pre-mutate value.


There is some ways you can solve that:

Using vanilla javascript

  • Add a computed property that returns your data property converting to a JSON string.
  • Use JSON.parse on your Watch function to convert the string back to a object.
data() {
  return {
    myData: {
      time: {

      }
    }
  }
},
computed: {
  computedMyData() {
    return JSON.stringify(this.myData);
  }
},
watch: {
  computedMyData: {
    handler(newValJSON, oldValJSON) {
      let newVal = JSON.parse(newValJSON),
          oldVal = JSON.parse(oldValJSON);
      
        console.log("NEW", newVal);
        console.log("OLD", oldVal);
      },
      deep: true
    }
  },
methods: {
  addData() {
    this.$set(this.myData.time, 'other','testing')
  }
}

Fiddle: https://jsfiddle.net/mLbuf6t0/

Using LODASH

  • Add a computed property that returns a deep clone from your data property with cloneDeep function.
data() {
  return {
    myData: {
      time: {

      }
    }
  }
},
computed: {
  computedMyData() {
    return _.cloneDeep(this.myData)
  }
},
watch: {
  computedMyData: {
    handler(newVal, oldVal) {            
      console.log("NEW", newVal);
      console.log("OLD", oldVal);
    },
    deep: true
  }
},
methods: {
  addData() {
    this.$set(this.myData.time, 'other','testing')
  }
}

Fiddle: https://jsfiddle.net/mLbuf6t0/2/

like image 75
João Hamerski Avatar answered Sep 14 '25 11:09

João Hamerski