Vue中有三种响应式数据:props,data,computed,它们都会在特定的条件下更新视图。但是有些时候如果需要对一个实例属性进行监视,并在该属性的值发生变化时执行一些操作,则可以使用Vue的watch
功能。而在Vue 3中,相比于watch
,watchEffect
是一个更加强大、更加灵活的监视选项,它可以自动追踪响应式变化,并立即执行传入的函数。
一、Vue WatchEffect概述
watchEffect
在Vue 3中是一个响应式工具函数,它可以执行一个函数并追踪其中用到的响应式依赖,并在任何该依赖发生改变的时候重新运行这个函数。watchEffect
用于监视一个响应式对象,以便在其属性变化时执行一些操作。
下面是watchEffect
的基本语法:
watchEffect(effect: Function, options: WatchEffectOptions): StopHandle
其中effect
为一个函数,在函数中可以访问响应式属性,如下面的代码所示:
import { reactive, watchEffect } from 'vue'
const state = reactive({
count: 0
})
watchEffect(() => {
console.log(state.count)
})
上面代码中,我们监听了state
对象中count
这个属性的值的变化,并在控制台输出变化后的新值。
二、WatchEffect处理对象
watchEffect
可以处理多种类型的对象,在这些不同类型的对象中,watchEffect
会自动跟踪其中任何数据属性的变化。
1、处理数组
下面是watchEffect
如何处理数组:
import { reactive, watchEffect } from 'vue'
const state = reactive({
todos: [
{ text: 'Learn Vue', done: false },
{ text: 'Learn Vuex', done: false },
{ text: 'Learn Vue Router', done: false }
]
})
watchEffect(() => {
state.todos.forEach(todo => {
console.log(todo.text)
})
})
在上面的代码中,我们监听todos
数组中每个对象的text
属性,并在控制台输出text
属性的值。
2、处理嵌套对象
watchEffect
能够处理嵌套对象,当里面的属性发生改变时,监听函数就会重新运行。
import { reactive, watchEffect } from 'vue'
const state = reactive({
person: {
name: 'Tom',
age: 20,
address: {
city: 'New York',
state: 'NY'
}
}
})
watchEffect(() => {
console.log(state.person.address.city)
})
上面代码中,我们监听state
对象中嵌套的person
对象的address
属性中的city
属性,当city
属性值发生变化时,监听函数将重新运行。
三、WatchEffect特征
watchEffect
与watch
有以下几个不同点:
watchEffect
是一个自动地、即时地追踪响应式依赖,并在任何该依赖发生改变的时候重新运行这个函数;而watch
是一个手动地监测特定数据的变化。watchEffect
函数不接收特定的数据,而是通过调用响应式对象中所有数据的getter来尝试捕获所依赖的数据;watch
则需要通过一个计算函数来确定它所依赖的特定数据,并在每个数据变化时触发回调。watchEffect
返回一个停止函数,该函数可用于停止监视;watch
则返回一个取消监听的函数。 下面我们来看一个具体的例子,使用watchEffect
实现一个简单的计数器:
import { reactive, watchEffect } from 'vue'
const state = reactive({
count: 0
})
watchEffect(() => {
console.log(`Count: ${state.count}`)
})
上面的代码中,我们定义了一个响应式的数据对象state
,其中包含一个count
属性,然后使用watchEffect
监听state.count
,当count
属性的值改变时,控制台会输出最新的count
值。
四、WatchEffect响应式的局限性
虽然watchEffect
可以处理多种类型的对象,包括对象、嵌套对象和数组,但是watchEffect
并不是完美的。在某些情况下,watchEffect
可能无法自动追踪响应式变化。下面是一些watchEffect
无法处理的情况:
- 普通对象属性
watchEffect
只会追踪响应式对象的值。如果在响应式对象中放置了一个非响应式对象,则watchEffect
将无法监听到该对象属性的变化。 - 动态添加属性或删除属性
在Vue 3中,已经可以动态添加/删除对象属性和数组元素,这些属性和元素将是非响应式的。这意味着,当我们使用watchEffect
监听对象属性或数组元素时,添加或删除属性/元素将不会触发监听函数。
五、WatchEffect高级特性
watchEffect
有一些高级用法,如:
1、WatchEffect函数和具体依赖的区别
watchEffect
可以监视计算属性或组合属性,但watchEffect
不会检查具体的依赖,而是对数据进行一次静态分析。下面是一个例子:
const state = reactive({
firstName: 'First Name',
lastName: 'Last Name'
})
watchEffect(() => {
console.log(`Full Name: ${state.firstName} ${state.lastName}`)
})
上面代码中,我们用watchEffect
监测state
对象的firstName
和lastName
属性。如果我们在输出语句中使用计算属性fullName
代替firstName
和lastName
,如下所示:
const state = reactive({
firstName: 'First Name',
lastName: 'Last Name'
})
watchEffect(() => {
const fullName = `${state.firstName} ${state.lastName}`
console.log(`Full Name: ${fullName}`)
})
这将使watchEffect
无法检测fullName
的依赖关系,因为它不知道fullName
是由哪些数据组成的。这将导致我们在watchEffect
中不得不写更多的响应式数据。
2、WatchEffect处理异步更新
有些情况下,watchEffect
监听的响应式数据的更新是异步的。在这种情况下,如果我们需要在watchEffect
监听回调函数中使用异步更新的响应式数据,需要使用Vue提供的“界面刷新同步保证”机制,即$nextTick()
函数。
下面是一个例子,演示了如何处理异步更新:
import { reactive, watchEffect } from 'vue'
const state = reactive({
count: 0
})
watchEffect(() => {
console.log(`Count: ${state.count}`)
Vue.nextTick().then(() => {
console.log(`Count (after DOM update): ${state.count}`)
})
})
setInterval(() => {
state.count++
}, 1000)
上面的代码中,我们用watchEffect
按秒监测state.count
的变化,每一次变化都输出count
的新值。为了处理异步更新,我们使用了Vue提供的$nextTick()
方法,它会在下一次DOM更新之后执行回调函数,以确保我们能够获取到更新后的值。
六、结论
Vue watchEffect
提供了一种更加灵活和高效的方式,能够方便地追踪响应式变化,并立即执行传入的函数。watchEffect
处理对象的能力很强,它能够处理多种类型的响应式依赖,包括对象、嵌套对象和数组。
watchEffect
的高级特性包括能够监视计算属性和处理异步更新。尽管watchEffect
有一些局限性,但它依然是Vue 3中响应式的一个非常强大的工具。