vue3中watch的用法,比2复杂很多。
function watch<T>(
source: WatchSource<T>,
callback: WatchCallback<T>,
options?: WatchOptions
): StopHandle
watch函数接受三个参数,
第一个监听的数据源:可以是一个函数返回一个值、ref、reactive、或者由以上三种组成一个数组(监听多个数据源)
第二个数据源变动时执行的回调函数,执行时机默认是渲染之前
第三个类似于2的参数,immediate、deep、flush(回调执行时机)
1:监听基本数据类型和一个函数,直接使用即可。
const a = reactive({b: 1})
watch(
() => a.b,
(value, oldValue) => {
console.log(value, oldValue)
}
)
2:监听多个数据源
const a = ref('aaa')
const b = ref('bbbb')
watch([a, b], ([a, b], [preva, prevb]) => {
})
注意:如果a和b在渲染之前都被改变,只执行一次,若一个在渲染前一个在渲染后,则回调执行两次
3:监听引用数据源,数据源定义分为ref和reactive
ref定义,数组中为基本数据类型,只能获取当前值,
如果数组中是引用数据类型,需要加deep才能获取当前值:
const arrayRef = ref([1, 2, 3, 4])
watch(
arrayRef,
(newValue, oldValue) => {
console.log('new', newValue, 'old', oldValue)
},
)
ref定义,获取老值和新值,
如果数组中是引用数据类型,需要加deep才能获取当前值和老值:
const arrayRef = ref([1, 2, 3, 4])
watch(
() => [...arrayRef.value],
(newValue, oldValue) => {
console.log('new', newValue, 'old', oldValue)
},
)
reactive 定义,只能获取新值
如果数组中是引用数据类型,不需要加deep,reactive默认添加:
const arrayRef = reactive([1, 2, 3, 4])
watch(arrayRef, (newValue, oldValue) => {
console.log('new', newValue, 'old', oldValue)
})
reactive 定义,可以获取新值和老值,
如果数组中是引用数据类型,需要加deep才能获取当前值:
const arrayRef = reactive([1, 2, 3, 4])
watch(
() => [...arrayRef],
(newValue, oldValue) => {
console.log('new', newValue, 'old', oldValue)
}
)
总结:如果直接监听数据源,无法获取老值,如果监听get函数,可以获取老值,如果数组中是引用数据类型,ref定义需要添加deep,reactive定义直接监听不需要加,监听get函数需要加。
watchEffect:
function watchEffect(
effect: (onCleanup: OnCleanup) => void,
options?: WatchEffectOptions
): StopHandle
type OnCleanup = (cleanupFn: () => void) => void
interface WatchEffectOptions {
flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}
type StopHandle = () => void
接受两个参数,
第一个是回调函数,在代码初始化时会立即执行,并且会同时收集依赖。回调函数有一个参数(OnCleanup),主要作用是在当该回调函数在执行任务时(还未执行完,比如在函数中包含异步函数),再次触发了该回调,这个时候在执行该回调之前会执行一次OnCleanup钩子。OnCleanup的执行时机可以简单理解为当该回调执行一次后,在该回调下次执行之前执行。
第二个是options参数。
例子:
const a = reactive({ b: 1 })
watchEffect(OnCleanup => {
console.log(a.b) // 收集依赖
let timer = setTimeout(() => {
console.log(2222) // 理论上应该执行两次,但是因为OnCleanup 所以 执行一次
}, 8000)
OnCleanup(() => {
console.log('执行OnCleanup')
clearTimeout(timer)
})
})
setTimeout(() => {
a.b = 3
}, 5000)