vue watch为什么触发两次
-
Vue中的watch选项用来观察数据的变化,并在数据变化时执行相应的操作。当我们设置了watch选项后,如果数据发生变化,watch会被触发。然而有时候会出现watch被触发了两次的情况。下面我将解释一下watch为什么会触发两次的原因。
-
初始化时触发
当组件创建时,Vue会对数据进行初始化,包括设置初始值。在初始化过程中,watch会对数据进行一次观察,并且会在初始值被设置时触发。这是watch第一次被触发的原因。 -
监听的数据发生变化时触发
watch选项是用来监听数据变化的,当被监听的数据发生变化时,watch会被触发。这是watch第二次被触发的原因。
但需要注意的是,并不是每次数据变化都会导致watch被触发两次。有时候只会触发一次,这取决于Vue的底层实现以及具体的应用场景。
在某些情况下,我们可能不希望watch被触发两次。这时可以使用immediate选项来设置watch是否在初始化时立即执行。将immediate设置为true,则watch会在初始化时立即执行一次,并且在数据变化时再次执行。将immediate设置为false,则watch只会在数据变化时执行。
此外,还有一种情况会导致watch触发两次,就是在watch中改变被监听的数据。当watch中改变了被监听的数据时,会再次触发watch。这是因为Vue会在watch被触发后检测被监听的数据是否发生变化,如果发生变化,会再次触发watch。
总结:watch会触发两次的原因是在初始化时会被触发一次,而当被监听的数据发生变化时会再次触发。可以通过immediate选项来控制watch是否在初始化时立即执行,并且在watch中改变被监听的数据会再次触发watch。
1年前 -
-
Vue的watch选项是用来监听数据变化的,当被监听的数据发生改变时,会触发相应的回调函数。然而,有时候我们会发现watch的回调函数会被触发两次。那么为什么会出现这种情况呢?
以下是可能导致watch触发两次的几个原因:
- 初始化时的初始化和真正的变化引起的
在Vue实例初始化时,会首先执行一次watch回调函数,这是因为Vue会在初始化过程中收集依赖项。之后,当数据发生真正的变化时,watch回调函数会再次触发。
例如,当我们设置一个初始值为0的数据,并在watch中监听这个数据:
data() { return { count: 0 } }, watch: { count(newVal, oldVal) { console.log('count changed:', newVal, oldVal); } }当Vue首次渲染时,会触发一次watch回调函数,打印出'count changed: 0 undefined'。之后,当我们通过改变count的值时,watch回调函数会再次触发,打印出对应的新旧值。
- 对象或数组的改变引起的
当监听的数据是对象或数组时,Vue默认会使用深度监听的方式。这意味着当对象或数组内部的内容发生变化时,也会触发watch回调函数。而对对象或数组的修改往往会引起多次触发。
例如:
data() { return { obj: { name: 'Tom', age: 18 } } }, watch: { obj: { deep: true, handler(newVal, oldVal) { console.log('obj changed:', newVal, oldVal); } } }当我们通过
this.obj.name = 'Jerry'来修改obj对象的name属性时,watch回调函数会触发两次,打印出两次不同的新旧值。- 监听多个数据引起的
当我们在watch选项中同时监听多个数据时,只要其中任何一个数据发生变化,watch回调函数就会触发一次。因此,如果多个数据同时发生变化,那么watch回调函数也会触发多次。
例如:
data() { return { firstName: 'Tom', lastName: 'Jerry' } }, watch: { firstName(newVal, oldVal) { console.log('first name changed:', newVal, oldVal); }, lastName(newVal, oldVal) { console.log('last name changed:', newVal, oldVal); } }当我们同时修改firstName和lastName时,watch回调函数会触发两次,分别打印出对应的新旧值。
- 立即执行选项引起的
在watch选项中,我们可以设置immediate为true来让watch回调函数在初始时立即执行一次。这就意味着watch回调函数会被调用两次,一次是在初始时立即执行,一次是在数据变化时触发。
例如:
data() { return { count: 0 } }, watch: { count: { immediate: true, handler(newVal, oldVal) { console.log('count changed:', newVal, oldVal); } } }当Vue首次渲染时,会触发一次watch回调函数,打印出'count changed: 0 undefined'。之后,当我们通过改变count的值时,watch回调函数会再次触发,打印出对应的新旧值。
- 监听computed属性引起的
当我们在watch中监听一个computed属性时,computed属性的依赖变化时会导致watch回调函数触发。由于computed属性的缓存特性,当computed属性的依赖发生变化时,会触发watch回调函数两次,第一次是在computed属性的依赖变化时立即执行,第二次是在watch选项中监听的数据变化时触发。
例如:
data() { return { firstName: 'Tom', lastName: 'Jerry' } }, computed: { fullName() { return this.firstName + ' ' + this.lastName; } }, watch: { fullName(newVal, oldVal) { console.log('full name changed:', newVal, oldVal); } }当我们修改firstName或lastName时,watch回调函数会触发两次,分别打印出对应的新旧值。
综上所述,Vue的watch选项可能会触发两次的原因有多种,这主要取决于监听的数据类型、监听的数据是否发生变化、是否设置了immediate等选项。在实际开发中,我们需要根据具体需求来进行调整和处理。
1年前 - 初始化时的初始化和真正的变化引起的
-
在Vue中,当使用
watch来监听数据时,有时候会发现watch会触发两次,造成一些不必要的性能消耗。这种情况通常出现在监听一个对象或数组的变化时。这个问题的根本原因是Vue的响应式系统。Vue是通过
Object.defineProperty来实现数据的响应式,当一个对象中的属性被访问或修改时,Vue会自动触发对应的getter和setter方法。而在watch中监听对象或数组时,当对象或数组发生变化时,Vue会通过重新设置它们的属性值来触发setter方法,从而导致watch被触发多次。解决这个问题有几种方法,下面进行详细介绍。
方法一:深度监听
首先,可以使用Vue提供的
deep选项来实现深度监听。深度监听会递归监听对象内部的所有属性,并在任何嵌套属性发生变化时触发watch。这样可以解决watch触发两次的问题。watch: { obj: { handler(newVal, oldVal) { // 处理逻辑 }, deep: true } }方法二:立即触发
另一种解决方法是使用Vue提供的
immediate选项。设置immediate为true时,会在watch被创建后立即执行一次handler函数,从而解决watch触发两次的问题。watch: { obj: { handler(newVal, oldVal) { // 处理逻辑 }, immediate: true } }方法三:手动检测
还有一种解决方法是使用
deep选项和手动检测对象变化的方法。通过创建一个副本来检测对象是否变化,从而避免了watch触发两次的问题。watch: { obj: { handler(newVal, oldVal) { // 检测对象是否变化 if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) { // 处理逻辑 } }, deep: true } }方法四:使用计算属性
最后一种方法是使用计算属性来代替
watch。计算属性是一个具有缓存功能的属性,当计算属性依赖的数据发生变化时,计算属性会重新计算,而不需要手动监听变化。computed: { objComputed() { // 处理逻辑 } }总结来说,
watch触发两次的问题是由于Vue的响应式系统所导致的。通过使用deep选项、immediate选项、手动检测变化或使用计算属性等方法,可以有效解决watch触发两次的问题,提高应用的性能。1年前