Search code examples
javascriptvue.js

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())?

Solution

  • 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);
      },
    );