侦听器

36 阅读2分钟

侦听器更新了新的API

watch

侦听类型可以是单个ref,也可以是getter函数,也可以是多个来源的数组; 侦听的属性发生了明确的改变,才会触发watch回调;

const x = ref(0)
const y = ref(0)

// 单个 ref
watch(x, (newX) => {
  console.log(`x is ${newX}`)
})

// getter 函数
watch(
  () => x.value + y.value,
  (sum) => {
    console.log(`sum of x + y is: ${sum}`)
  }
)

// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
  console.log(`x is ${newX} and y is ${newY}`)
})

不能直接侦听响应式对象的属性,但是可以用getter侦听响应式对象的属性

const obj = reactive({ count: 0 })

// 错误,因为 watch() 得到的参数是一个 number
watch(obj.count, (count) => {
  console.log(`count is: ${count}`)
})

// 提供一个 getter 函数
watch(
  () => obj.count,
  (count) => {
    console.log(`count is: ${count}`)
  }
)

深层侦听器

触发深层侦听器的方式, 1.直接watch一个响应式对象;2.设置{deep:true}

深层监听的问题

深层监听中,如果监听的是一个对象,那么更新对象内的属性,则会造成监听的回调函数内的新值和老值相同; 整个替换调监听的对象,才能获取不同新值和老值.

const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
  // 在嵌套的属性变更时触发
  // 注意:`newValue` 此处和 `oldValue` 是相等的
  // 因为它们是同一个对象!
  console.log('newValue, oldValue', newValue.count, oldValue.count); // 是相等的
})
const objIncreament = () => {
    obj.count++;
}
// 仅当 state.someObject 被替换时触发, 而且能得到oldVal值
const state = reactive({
    someObject: {a: 1}
})
watch(
    () => state.someObject,
    (val, oldVal) => {
        console.log('state.someObject', val, oldVal);
    }
)
// 整个替换调监听的对象
state.someObject = {b:2}
console.log(state);

watchEffect

监听回调会立即执行一次; 会自动跟踪依赖关系,当依赖发生变更的时候执行回调函数;

// 当url改变的时候,会再次执行watchEffect的回调函数
const url = ref('https://api.github.com/repos/vuejs/core/commits?per_page=3&sha=')
const data = ref(null)

watchEffect(async () => {
    const response = await fetch(url.value)
    data.value = await response.json()
    console.log('fetchData', data.value);
})

回调的触发时机

默认情况下, 回调函数会在 Vue 组件更新之前被调用, 所以要在回调函数内获取更新之后的DOM, 需要设置{flush: 'post'}, 或者使用watchPostEffect

watchPostEffect

回调函数内获取更新之后的DOM

停止侦听器

在 setup() 或 <script setup> 中用同步语句创建的侦听器,会自动绑定到宿主组件实例上,并且会在宿主组件卸载时自动停止。因此,在大多数情况下,你无需关心怎么停止一个侦听器。

如果用异步回调创建一个侦听器,那么它不会绑定到当前组件上,你必须手动停止它

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

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

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