一、watch
watch() 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。
watch 有三个参数:
1、第一个参数是需要侦听的数据
(1)一个 ref
或者一个响应式对象
(2)一个函数,返回一个值
(3)由以上类型的值组成的数组
2、第二个参数是数据发生变化时的回调
第二个参数是在发生变化时要调用的回调函数。 这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。 该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。
//当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。
watch([aRef, bRef], ([newA, newB], [prevA, prevB]) => {
/* ... */
})
3、第三个参数是一个可选的对象
immediate
:在侦听器创建时立即触发回调。第一次调用时旧值是undefined。
deep
:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。flush
:回调函数的刷新时机。onTrack / onTrigger
:调试侦听器的依赖。
flush
pre
(默认)
侦听器将在组件渲染之前执行。post
将会使侦听器延迟到组件渲染之后再执行。sync
响应式依赖发生改变时立即触发侦听器。
onTrack / onTrigger
onTrack
依赖项被追踪时被调用,只会执行一次。 onTrigger
依赖项变更导致副作用被触发时被调用。只在开发模式下生效。
注意事项
1、当侦听一个响应式对象时,侦听器会自动启用深层模式。
const state = reactive({ count: 0 })
watch(state, () => {
/* 深层级变更状态所触发的回调 */
})
2、watch
只能监听响应式数据:ref
定义的属性和 reactive
定义的对象,如果直接监听 reactive
定义对象中的属性是不允许,只能使用函数转换一下,就是官网说的监听一个 getter。
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
},
{
deep: true
}
)
3、侦听 一个 ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
二、watchEffect()
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行
watchEffect 有两个参数
1、第一个参数是数据发生变化时执行的回调函数。
watchEffect(() => {
//监听state.str
console.log(state.str)
// 会在 props 变化时打印
console.log(a, b, c)
})
2、第二个参数是一个可选的对象,支持 flush 和 onTrack / onTrigger 选项,功能和 watch 相同。
watchEffect(() => {}, {
flush: 'post',
onTrack(e) {
debugger
},
onTrigger(e) {
debugger
}
})
注意
1、watchEffect
不支持深度监听,如果监听 reactive
定义的对象是不起作用的,只能监听对象中的属性。
2、3.2
版本以上可以用 watchPostEffect
watchSyncEffect
代替 flush: 'post'
flush: 'sync'。
3、watchEffect
动态加入的依赖不会被清除。
4、watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式属性。
三、什么时候应该使用 watch 和 watchEffect
- 如果需要依赖旧值必须使用
watch。
- 需要深度监听时必须使用
watch。
watchEffect
侦听数据变化写法比较简单,但是不能轻易的操作依赖值,否则会重复触发。- 如果回调函数不依赖侦听值那么需要用
watch。
- 需要明确知道由哪个状态触发的则必须用
watch。
四、访问 Vue 更新之后的 DOM
在 Vue2.x 中, 使用 nextTick, 在Vue3 中,watch / watchEffect 指明 flush: 'post' 选项 即可。
//watch
watch(source, callback, {
flush: 'post'
})
//watchEffect
watchEffect(callback, {
flush: 'post'
})
//watchEffect也可以使用watchPostEffect
import { watchPostEffect } from 'vue'
watchPostEffect(() => {
/* 在 Vue 更新后执行 */
})