侦听器更新了新的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()