[vue3] watch和watchEffect简记
watch的数据源
watch函数的第一个参数是监听的数据源,可以是:
- ref和computed创建的响应式数据;
- reactive创建的响应式对象;
- getter函数;
- 多个数据源组成的数组;
注:
- 响应式对象的属性需要使用getter监听。
- 当数据源是响应式对象时,其属性的变更会触发回调函数,但是接收到的
newValue
和oldValue
是一样的,因为对象的引用是同一个。 - 和上一条不同,如果数据源是一个“返回响应式对象”的getter,除非对象的引用变更,否则不会触发回调函数。可以使用
deep
监听其所有的属性,使用递归实现,开销大,谨慎使用。 - 一般watch是先设置,监听到变化后再触发。如果需要设置的时候就先立即触发一次,使用
immediate
。
watchEffect
特点:
- watchEffect不需要指定依赖,只需要传入回调函数,它会自动追踪函数内部依赖的响应式数据,并在这些数据发生变更时触发回调函数。
- 对于有多个依赖项的监听器来说,不需要手动维护依赖列表,比watch方便很多。
- watchEffect默认是
immediate
的,即立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。 - watchEffect只在同步执行期间追踪依赖,对于使用async await的异步回调函数,只有在第一个await之前访问的响应式数据会被追踪。
侦听器回调的触发时机
响应式状态的变更会同时触发:Vue组件更新和侦听器回调。
默认情况下,先执行侦听器回调,再执行Vue组件更新。这意味着在侦听器回调中的DOM是Vue更新组件之前的状态。
可以使用flush: post
选项,调整这一顺序:
watch(source, callback, {
flush: 'post'
})
watchEffect(callback, {
flush: 'post'
})
如果觉得配置选项太麻烦,对于watchEffect,有一个便捷的替代品:watchPostEffect
import { watchPostEffect } from 'vue'
watchPostEffect(() => {
/* 在 Vue 更新后执行 */
})
停止侦听器
同步创建的侦听器会绑定在宿主组件实例上,并会在组件卸载时自动停止。
当异步创建了一个侦听器时,它不会被绑定到组件上,为了防止内存泄漏,需要手动停止。
watch和watchEffect函数存在一个返回值,是一个用于停止侦听器的函数:
const unwatch = watchEffect(() => {})
// ...当该侦听器不再需要时
unwatch()
尽量不要使用异步创建侦听器,如果需要等待异步数据,可以使用条件式的侦听逻辑:
// 需要异步请求得到的数据
const data = ref(null)
watchEffect(() => {
if (data.value) {
// 数据加载后执行某些操作...
}
})