Summary of watch and watchEffect in Vue3

watchBoth and watchEffectare vue3listeners, but there are differences in writing and usage. This is mainly to introduce the usage of watchand watchEffectand the differences between them.

How watches work : Listen to a specific data source and perform side effects in a callback function. It is lazy by default - the callback is only executed when the listened source changes, however, you can configure immediate to true to specify the initial execution immediately the first time. Deep monitoring can be specified by configuring deep to true

immdiate : By default, the listener needs to change the value behind the data to take effect. If the listener needs to take effect as soon as it enters the page, you need to use immediate

deep : By default, the listener will only monitor the changes of the data itself. If you want to monitor deeply, you need to use deep. immediate and deep are configured in the third parameter object

The first parameter: who to listen to, the second parameter: the callback function, the third parameter: the configuration object

watch monitors a single data

<template>
    <input type="text" v-model="text1" />
</template>

<script setup> 
    import { ref, watch } from 'vue'
    const text1 = ref('')

    watch(text1, (newVal, oldVal) => {console.log('监听单个数据', newVal, oldVal)
    }) 
</script> 

Listen to multiple data (initial value is empty, and not printed)

<template>
    <input type="text" v-model="text1" placeholder="text1值" />
    <hr /> 
    <input type="text" v-model="text2" placeholder="text2值" /> 
</template> 
<script setup>
import { ref, watch, reactive } from 'vue'
const text1 = ref('') 
const text2 = ref('')  
watch([text1,text2], (newValue, oldValue) => {
    console.log('监听一组数据变化', newValue, oldValue)
})

// { immediate: true }
</script> 

Listening to an object - the question

<template>
name: <input type="text" v-model="student.name" />
<hr/>
age: <input type="number" v-model="student.age" />
</template>

<script setup> import { reactive, watch } from 'vue'

const student = reactive({name: '',age: ''
})

watch(student, (newVal, oldVal) => {
console.log('newVal', newVal)
console.log('oldVal', newVal)
}) </script> 

Listen to a certain value of the object

<template>
    name: <input type="text" v-model="student.name" />
    <hr />
    age: <input type="number" v-model="student.age" />
</template> 
<script lang="ts" setup>
import { reactive, watch } from 'vue' 
const student = reactive({
    name: '', age: ''
}) 
watch(() => student.name, (newVal, oldVal) => {
    console.log('newVal', newVal)
    console.log('oldVal', newVal)
}, {
    deep: true, immediate: true
}) 

</script> 

Encountered pits:

1. When monitoring the responsive data defined by reactive: oldValue cannot be obtained correctly, and deep monitoring is forced to be turned on (deep configuration is invalid)

<template>
    <h2>姓名:{
   
   { person.name }}</h2>
    <h2>年龄:{
   
   { person.age }}</h2>
    <h2>薪资:{
   
   { person.job.j1.salary }}K</h2>
    <button @click="person.name += '~'">修改姓名</button>
    <button @click="person.age++">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button>

    <hr />
    <input type="text" v-model="text1" />
</template>
   
<script>
import { reactive, watch, ref } from 'vue'
export default {
    setup() {
        //数据 
        let person = reactive({
            name: '张三',
            age: 18,
            job: {
                j1: {
                    salary: 20
                }
            }
        })
        const text1 = ref('')
        /* 情况三:监视reactive所定义的一个响应式数据的全部属性
                       1.注意:此处无法正确的获取oldValue
                       2.注意:强制开启了深度监视(deep配置无效)-不管嵌套有多深
           */
        watch(person, (newValue, oldValue) => {
            console.log('person变化了', newValue, oldValue)
        }, { deep: false }) //此处的deep配置无效 */

        watch(text1, (newVal, oldVal) => {
            console.log('监听单个数据', newVal, oldVal)
        })
        //返回一个对象(常用)
        return {
            person, text1
        }
    }
}
</script>

2. When monitoring a certain attribute in the responsive data defined by reactive: the deep configuration is valid

<template>
    <h2>姓名:{
   
   { person.name }}</h2>
    <h2>年龄:{
   
   { person.age }}</h2>
    <h2>薪资:{
   
   { person.job.j1.salary }}K</h2>
    <button @click="person.name += '~'">修改姓名</button>
    <button @click="person.age++">增长年龄</button>
    <button @click="person.job.j1.salary++">涨薪</button> 
    <hr />
    <input type="text" v-model="text1" />
</template>
   
<script>
import { reactive, watch, ref } from 'vue'
export default {
    setup() {
        //数据 
        let person = reactive({
            name: '张三',
            age: 18,
            job: {
                j1: {
                    salary: 20
                }
            }
        })
        const text1 = ref('')
        /* 情况三:监视reactive所定义的一个响应式数据的全部属性
                       1.注意:此处无法正确的获取oldValue
                       2.注意:强制开启了深度监视(deep配置无效)-不管嵌套有多深
           */
        watch(person, (newValue, oldValue) => {
            console.log('person变化了', newValue, oldValue)
        }, { deep: false }) //此处的deep配置无效 */

        watch(text1, (newVal, oldVal) => {
            console.log('监听单个数据', newVal, oldVal)
        })
        watch(() => person.age, (newValue, oldValue) => {
            console.log('person的age变化了', newValue, oldValue)
        }, { deep: true }) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
        //返回一个对象(常用)
        return {
            person, text1
        }
    }
}
</script>

3. When using ref to define an array: (when changeArr is triggered, it cannot be monitored)

<template>
    <button @click="changeArr">按钮</button>
</template>
   
<script>
import { reactive, watch, ref } from 'vue'
export default {
    setup() {
        const array = ref([1, 2, 3]);
        const changeArr = () => {
            console.log('触发');
            array.value = [];
        }
        watch(array.value, (now, old) => {
            console.log(now, old); // 触发changeArr的时候,监听不到
        })

        return {
            array, changeArr
        }
    }
}
</script>

solution:

<template>
    <button @click="changeArr">按钮</button>
</template>
   
<script>
import { reactive, watch, ref } from 'vue'
export default {
    setup() {
        const array = ref([1, 2, 3]);
        const changeArr = () => {
            console.log('触发');
            array.value = [];
        }
        // watch(array.value, (now, old) => {
        //     console.log(now, old); // 触发changeArr的时候,监听不到
        // })

        watch(() => [array.value], (now, old) => {
            console.log(now, old)
        })


        return {
            array, changeArr
        }
    }
}
</script>

watchEffect

Features of the watchEffect function:

  • advantage:

    • Dependencies will be collected automatically, and there is no need to manually pass the listening content - automatically listening to the responsive data used in the callback function.

    • The default immdiate is true, so it will be executed immediately during initialization.

  • shortcoming:

    • Unable to get the value before the change (oldVal).

watch()It is executed lazily: the callback will only be executed when the data source changes. But in some scenarios, we want to execute the callback immediately when the listener is created.

watchEffectIt is equivalent to watchmerging the dependency source and the callback function. When any reactive dependencies you use are updated, the callback function will be re-executed. Unlike watch, watchEffectthe callback function will be executed immediately (ie { immediate: true })

In short, watchEffect is a reactive API in Vue3 that allows you to monitor reactive state changes and trigger side effects when they change. This feature is very useful. When we need to operate on responsive data, we can react immediately after listening to changes.

<template>
name: <input type="text" v-model="student.name" />
age: <input type="number" v-model="student.age" />
</template>

<script setup>

import { reactive, watchEffect } from 'vue'

const student = reactive({name: '',age: ''
})
watchEffect(() => {console.log('name: ',student.name, 'age: ', student.age)
}) 

</script> 

watcheffect stop listening

<template>
    <div>
        <input type="text" v-model="obj.name">
        <button @click="stopWatchEffect">停止监听</button>
    </div>
</template>
  
<script>
import { reactive, watchEffect } from 'vue';
export default {
    setup() {
        let obj = reactive({
            name: 'zs'
        });
        const stop = watchEffect(() => {
            console.log('name:', obj.name)
        })
        const stopWatchEffect = () => {
            console.log('停止监听')
            stop();
        }

        return {
            obj,
            stopWatchEffect,
        }
    }
}
</script> 

side effects of watchEffect

What is a side effect ( side effect), simply speaking, a side effect is to perform some kind of operation, such as modification of external variable data or variables, call of external interface, etc. watchEffectThe callback function is a side effect function, because we use watchEffectit to perform certain operations after listening to changes in dependencies.

Vue3The function passed in by the watchEffectlistening side effect can receive a onInvalidatefunction as an input parameter, which is used to register the callback when the cleanup fails

This invalidation callback will be triggered when:

  • when the side effect is about to be re-executed (i.e. the value of the dependency changes)

  • The listener is stopped (stop listening by explicitly calling the return value, or implicitly calling stop listening when the component is unmounted)

import { watchEffect, ref } from 'vue'

const count = ref(0)
watchEffect((onInvalidate) => {
  console.log(count.value)
  onInvalidate(() => {
    console.log('执行了onInvalidate')
  })
})

setTimeout(()=> {
  count.value++
}, 1000) 

The order in which the above code prints is: 0-> 执行了onInvalidate,最后执行->1

countAnalysis: The value is printed first during initialization 0, and then the timer countupdates the value to 1, and the side effect is about to be re-executed at this time, so onInvalidatethe callback function will be triggered, printed 执行了onInvalidate, and then the side effect function is executed to print countthe value 1.

import { watchEffect, ref } from 'vue'

const count = ref(0)
const stop = watchEffect((onInvalidate) => {
  console.log(count.value)
  onInvalidate(() => {
    console.log('执行了onInvalidate')
  })
})

setTimeout(()=> {
  stop()
}, 1000)

The above code: When we show that the execution stopfunction stops listening, onInvalidatethe callback function will also be triggered at this time. Similarly, watchEffectwhen the component is uninstalled, the function will be implicitly stopcalled to stop listening, so onInvalidatethe callback function can also be triggered.

【Notice】:

watchEffectIt will be used extensively in Vue3 development. Here are a few points for attention:

  1. If there are multiple negative effects, do not glue them together, it is recommended to write more than one watchEffect.

watchEffect(() => {
  setTimeout(() => console.log(a.val + 1), 1000);
  setTimeout(() => console.log(b.val + 1), 1000);
});
//错误的

These two setTimeouts are two irrelevant effects, you don’t need to monitor a and b at the same time, you can write them separately

watchEffect(() => {
  setTimeout(() => console.log(a.val + 1), 1000);
});

watchEffect(() => {
  setTimeout(() => console.log(b.val + 1), 1000);
});

2. watchEffectIt can also be placed in other life cycle functions

onMounted(() => {
  watchEffect(() => {
    // access the DOM or template refs
  });
}

Summarize

watch

Lazy execution of side effects - you need to manually specify what to listen to, and also specify the callback to listen to.

The default immdiate is false, so it will not be executed during initialization, and the callback will only be executed when the listened source data changes.

No return value is required.

You can get the value before the change (oldVal)

watchEffect

Automatically collect dependencies, no need to manually pass listening content - automatically listen to the responsive data used in the callback function

The default immdiate is true, so it will be executed immediately during initialization, and the callback will also be executed when the source data changes.

No return value is required.

Unable to get the value before the change (oldVal)

Guess you like

Origin blog.csdn.net/zz130428/article/details/130614200