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>