Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue watch() outputs same oldValue and newValue

When doing my frontend Vue project, I have the need of executing certain steps when element(s) are pushed into the list in data. However, when I pushed some initial values into the list in mounted(), the console.log() in the corresponding watch() outputs the same value for the newVal and oldVal parameter values.

Javascript/Vue code:

let app = new Vue({
    el: "#app",
    data: {
        testList: [],
    },
    mounted: function() {
        this.testList.push('a');
        this.testList.push('b');
        this.testList.push('c');
    },
    watch: {
        testList: {
            handler: function(newVal, oldVal) {
                console.log("new", newVal);
                console.log("old", oldVal);
            },
        },
    }
});

The console logging information: Console logging information

  1. Why do the newVal and oldVal hold the same value?
  2. Why isn't the watch() function being executed three times (since I pushed three times in mounted())?
like image 500
Power_tile Avatar asked Sep 13 '25 16:09

Power_tile


2 Answers

In addition, if someone is having this problem when watching nested properties changes, and using flag deep: true, it's expected that newValue and oldValue are the same (reference).

To overcome the issue, you could add computed property wrapping the data object that should be watched, and watch for changes on the computed property instead.

export default {
name: 'ExampleComponent',
data () {
    return {
        exampleObject: {
            name: 'User',
            email: 'Email'
        }
    }
},

computed: {
    computedObjectToBeWatched () {
        return Object.assign({}, this.exampleObject)
    }
},

watch: {
    computedObjectToBeWatched: {
        deep: true,
        handler (value, oldValue) {
            if (value.name !== oldValue.name) {
                console.log('changes occured')
            }
        }
    }
}

For Vue3/Composition API:

const usedToBeWatched = ref([]);
const watchedComputed = computed(() => structuredClone(toRaw(usedToBeWatched.value)));

watch(
  watchedComputed,
  (newVal, oldVal) => {
    console.log('watchedComputed', newVal, oldVal);
  },
);
like image 156
equi Avatar answered Sep 15 '25 05:09

equi


I have changed two thing

  1. do clone in watch
  2. added computed

It works fine now.

console.clear();

let app = new Vue({
    el: "#app",
    data: {
        testList: ['old'],
    },
    mounted: function() {
        this.testList.push('a');
        this.testList.push('b');
        this.testList.push('c');
    },
    watch: {
        testListClone: { //<-- Edited
            handler: function(newVal, oldVal) {
                console.log("new", newVal);
                console.log("old", oldVal);
            },
        },
    },
  computed:{  //<-- Added
    clonedItems: function(){
       return JSON.parse(JSON.stringify(this.testList))
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>

<div id="app"></div>
like image 33
GMKHussain Avatar answered Sep 15 '25 06:09

GMKHussain