_
2024/4/3 00:14:002076

watch和watchEffect

侦听器还没有讲完,为了降低每一节课的学习时间,我们分两节课讲。

即时回调的侦听器

watch 默认是懒执行的:仅当数据源变化时,才会执行回调。但在某些场景中,我们希望在创建侦听器时,立即执行一遍回调。举例来说,我们想请求一些初始数据,然后在相关状态更改时重新请求数据。

将immediate属性设置为true,将会在启动时就执行一次

watch(
  userinfo,
  (newValue,oldValue)=>{
    console.log(newValue)  //首次执行结果===》默认数据 {name:"小朱"}
    console.log(oldValue)  //首次执行结果===》未定义之前的数据 undefined
  },
  { immediate: true }
)

一次性侦听器

每当被侦听源发生变化时,侦听器的回调就会执行。如果希望回调只在源变化时触发一次,请使用 once: true 选项。

watch(
  userinfo,
  (newValue,oldValue)=>{
    console.log(newValue)  
    console.log(oldValue) 
  },
  { once: true }
)

watchEffect

我们使用watch来监听多条数据源时处理起来是比较麻烦的,那么watchEffect又为我们提供另一种写法。

第一个参数就是要运行的副作用函数。这个副作用函数的参数也是一个函数,用来注册清理回调。清理回调会在该副作用下一次执行前被调用,可以用来清理无效的副作用,例如等待中的异步请求 (参见下面的示例)。

第二个参数是一个可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖

watchEffect() 不需要我们主动提供侦听数据源,它会自动跟踪回调里的响应式依赖,并且watchEffect会自动触发首次执行类似于(watch+{ immediate: true }) 。

watchEffect(()=>{
   console.log(userinfo.name)
   console.log(count.value)
})

在回调函数里面使用到响应式变量,无论哪一个发生变化都会触发回调执行。比较适合用于处理 既需要启动执行又需要依赖某个数据执行的业务效果

watchEffect() 可能会比深度侦听器更有效,因为它将只跟踪回调中被使用到的属性,而不是递归地跟踪所有的属性

清理无效的副作用

第一个参数就是要运行的副作用函数。这个副作用函数的参数也是一个函数,用来注册清理回调。清理回调会在该副作用下一次执行前被调用,可以用来清理无效的副作用。

watchEffect((onCleanup)=>{
    console.log(userinfo.name)
    onCleanup(()=>{
       console.log("清楚副作用")
    })
})

侦听器的触发时机

不管是watch还是watchEffect我们都可以自定义侦听器回调的执行时间,默认都是在组件渲染前执行,我们可以通过设置flush: 'post' 让它变成在组件渲染后执行,这时候可以方便我们呢获取dom

watch(source, callback, {
  flush: 'post'
})

watchEffect(callback, {
  flush: 'post'
})

关于组件后执行侦听器 对于还可以使用watchPostEffect()

watchPostEffect(() => {
  /* 在 Vue 更新后执行 */
})

同步侦听器

你还可以创建一个同步触发的侦听器,它会在 Vue 进行任何更新之前触发:

watch(source, callback, {
  flush: 'sync'
})

watchEffect(callback, {
  flush: 'sync'
})

同步触发的 watchEffect() 有个更方便的别名 watchSyncEffect()

import { watchSyncEffect } from 'vue'

watchSyncEffect(() => {
  /* 在响应式数据变化时同步执行 */
})

停止侦听器

大多数情况下,侦听器不需要我们主动去停止的,它会随着组件的销毁而被停止。

但是侦听器必须用同步语句创建:如果用异步回调创建一个侦听器,那么它不会绑定到当前组件上,你必须手动停止它,以防内存泄漏。

<script setup>
import { watchEffect } from 'vue'

// 它会自动停止
watchEffect(() => {})

// ...这个则不会!
setTimeout(() => {
  watchEffect(() => {})
}, 100)
</script>

要手动停止一个侦听器,请调用 watch 或 watchEffect 返回的函数:

const unwatch = watchEffect(() => {})

// ...当该侦听器不再需要时
unwatch()

使用侦听器时建议大家还是选择同步创建监听器,而非必要使用异步创建侦听器,避免用了之后出现一些意想不到的问题