When asynchronous or expensive operations need to be performed when data changes, the Watch option provides a more generic way to respond to changes in data.

The basic usage of watch

An example of listening on an object’s internal properties via an object:

<template>
    <div>
        <p>{{ obj.a }}</p>
        <input v-model="obj.a" />
        <p>{{ obj.b }}</p>
        <input v-model.number="obj.b" />
    </div>
</template>
<script>
export default {
    data () {
        return {
            obj: {
                a: ' '.b: 18}}},watch: {
        obj: function (val, oldVal) {
            console.log(val.a, oldVal.a, "changed")}}}</script>
Copy the code

At this point, you can’t listen for the change of a property in the object

Listen for the inner data of the object. In addition, the handler obtains the same new value as the old value and executes the change of other values in the object

Handler method and deep property

Modify the listening as follows:

watch: {
    obj: {
        handler: function (val, oldVal) {
            console.log(val.a, oldVal.a, "changed")},deep: true}}Copy the code

The deep attribute listens deeply and traverses layer by layer. Changes to attribute B also trigger handler methods, which are particularly costly in performance. And you can’t get oldVal because the Pointers point to the same thing.

Values of reference types require computed processing

Optimization: use computed properties to process the value of the reference type. After deep copy, the oldVal value is perfectly retrieved

computed: {
    objClone () {
        return JSON.parse(JSON.stringify(this.obj))
    }
},
watch: {
    objClone: {
        handler: function (val, oldVal) {
            console.log(val.a, oldVal.a, "changed")},deep: true}}Copy the code

Listen for changes to A directly using strings

In this way, changes in other attributes do not trigger listening on A

watch: {
    "obj.a": function (val, oldVal) {
        console.log(val, oldVal, "changed")}}Copy the code

The immediate attribute

The listener is executed immediately after it starts, but it is important to note that oldVal is undefined.

watch: {
    objClone: {
        handler: function (val, oldVal) {
            console.log(val.a, oldVal.a, "changed")},deep: true.immediate: true}}Copy the code

Matters needing attention

  • You should not use the arrow function to define the watcher function; the arrow function this is undefined
  • Add this.obj.c = “”, delete this.b does not trigger handler, Should use this. The set (enclosing obj, “c”, “”) and enclosing the set (enclosing obj,” c “, “”) and enclosing the set (enclosing obj,” c “, “”) and enclosing the delete (enclosing obj,” b “)
  • The watch function in the component option is destroyed when the component is destroyed

Vue instance method this.$watch

Implementation of obJ listening

Obj, and can obtain the value of oldVal

<template>
    <div>
        <p>{{ obj.a }}</p>
        <input v-model="obj.a" />
        <p>{{ obj.b }}</p>
        <input v-model.number="obj.b" />
    </div>
</template>
<script>
let unwatch = null
export default {
    data () {
        return {
            obj: {
                a: ' '.b: 18
            }
        }
    },
    mounted () {
        unwatch = this.$watch(function () {
            return JSON.parse(JSON.stringify(this.obj))
        }, function (val, oldVal) {
            console.log(val.a, oldVal.a, 'changed')}, {deep: true
        })
    },
    beforeDestroy () {
        unwatch()
    }
}
</script>

Copy the code

This.$watch listens for data changes and needs to be unregistered manually when the component is destroyed. The cancel watch function returned by logout mode to stop triggering the callback.

Use the immediate attribute

Immediate: true Cancels listening in the callback function

Execute immediately to trigger the callback. In this case, to cancel the listening in the callback, you need to add fault tolerance to check whether unwatch exists

mounted () {
    unwatch = this.$watch(function () {
        return JSON.parse(JSON.stringify(this.obj))
    }, function (val, oldVal) {
        if (unwatch) {
            unwatch()
        }
    }, {
        deep: true.immediate: true})}Copy the code

Array responsive listening method

  • this.$set()
  • ‘push’, ‘pop’, ‘shift’, ‘unshift’, ‘splice’, ‘sort’, ‘reverse’ are overridden prototype methods

Component overuse results in invalid dynamic routing parameters

Watch for changes to $route

<template>
    <div></div>
</template>
<script>
export default {
    data () {
        return {}
    },
    mounted () {
        console.log("mouted".this.$route.params.id)
    },
    watch: {
        $route: function (to, from) {
            console.log("watch", to.params.id)
        }
    }
}
</script>
Copy the code