您的位置:

Vue WatchEffect详解

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有以下几个不同点: 1、WatchEffect是一个自动地、即时地追踪响应式依赖,并在任何该依赖发生改变的时候重新运行这个函数;而watch是一个手动地监测特定数据的变化。 2、WatchEffect函数不接收特定的数据,而是通过调用响应式对象中所有数据的getter来尝试捕获所依赖的数据;watch则需要通过一个计算函数来确定它所依赖的特定数据,并在每个数据变化时触发回调。 3、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无法处理的情况: 1、普通对象属性 WatchEffect只会追踪响应式对象的值。 如果在响应式对象中放置了一个非响应式对象,则 WatchEffect 将无法监听到该对象属性的变化。 2、动态添加属性或删除属性 在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中响应式的一个非常强大的工具。