Bootstrap

vue3监听器

1.侦听数据源类型

watch 的第一个参数可以是不同形式的“数据源”:它可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组

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}`)
})

2. 在监听响应式对象里的值时,需要提供一个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}`)
  }
)

3. 深度监听和立即执行

watch(
  () => state.someObject,
  (newValue, oldValue) => {
    // 注意:`newValue` 此处和 `oldValue` 是相等的
    // *除非* state.someObject 被整个替换了
  },
  { deep: true },
{ immediate: true }
)

4. 一次性侦听器

watch(
  source,
  (newValue, oldValue) => {
    // 当 `source` 变化时,仅触发一次
  },
  { once: true }
)

5. watchEffect()

(1)watch只监听明确了的数据源,只有在数据源变化时触发

(2)watchEffect可以监听所有能访问到的响应式属性

1.使用watch
const todoId = ref(1)
const data = ref(null)

watch(
  todoId,
  async () => {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
    )
    data.value = await response.json()
  },
  { immediate: true }
)


2.使用watchEffect
watchEffect(async () => {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
  )
  data.value = await response.json()
})

这里就会自动追踪 todoId.value 作为依赖,每当 todoId.value 变化时,回调会再次执行

6. 如果在监听一个id值时,会执行异步请求,但是如果在请求完成之前 id 发生了变化怎么办

可以使用onWatcherCleanup() API 来注册一个清理函数,重新调用

但是onWatcherCleanup() 只能在同步执行期间调用

import { watch, onWatcherCleanup } from 'vue'

watch(id, (newId) => {
  const controller = new AbortController()

  fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
    // 回调逻辑
  })

  onWatcherCleanup(() => {
    // 终止过期请求
    controller.abort()
  })
})

如果需要在异步时调用,可以使用onCleanup

onCleanup 函数还作为第三个参数传递给侦听器回调,以及 watchEffect 作用函数的第一个参数

watch(id, (newId, oldId, onCleanup) => {
  // ...
  onCleanup(() => {
    // 清理逻辑
  })
})

watchEffect((onCleanup) => {
  // ...
  onCleanup(() => {
    // 清理逻辑
  })
})

7.回调的触发时机

正常watch会在dom更新之前调用,但是如果当需要根据数据的变化来执行一些依赖于最新DOM状态的操作时,就需要在DOM更新之后调用,就可以使用flush: 'post'

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

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

----------------------------------

watchEffect添加flush: 'post'还可以使用下面的写法:
import { watchPostEffect } from 'vue'

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

8.侦听器一般同步使用,特殊情况会异步使用,而在异步使用时,需要手动的停止侦听器.

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

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

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


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

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

;