官方文档:https://cn.vuejs.org/api/reactivity-core.html#watcheffect
也就是说当使用他们两个时候,使用完成之后要及时停止他们,防止一直在运行,停止他们之后,也可以再次开启。
watchEffect()
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
类型
function watchEffect(
effect: (onCleanup: OnCleanup) => void,
options?: WatchEffectOptions
): WatchHandle
type OnCleanup = (cleanupFn: () => void) => void
interface WatchEffectOptions {
flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}
interface WatchHandle {
(): void // 可调用,与 `stop` 相同
pause: () => void
resume: () => void
stop: () => void
}
详细信息
第一个参数就是要运行的副作用函数。这个副作用函数的参数也是一个函数,用来注册清理回调。清理回调会在该副作用下一次执行前被调用,可以用来清理无效的副作用,例如等待中的异步请求 (参见下面的示例)。
第二个参数是一个可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖。
默认情况下,侦听器将在组件渲染之前执行。设置 flush: 'post'
将会使侦听器延迟到组件渲染之后再执行。详见回调的触发时机。在某些特殊情况下 (例如要使缓存失效),可能有必要在响应式依赖发生改变时立即触发侦听器。这可以通过设置 flush: 'sync'
来实现。然而,该设置应谨慎使用,因为如果有多个属性同时更新,这将导致一些性能和数据一致性的问题。
返回值是一个用来停止该副作用的函数。
示例
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> 输出 0
count.value++
// -> 输出 1
副作用清除:
watchEffect(async (onCleanup) => {
const { response, cancel } = doAsyncWork(id.value)
// `cancel` 会在 `id` 更改时调用
// 以便取消之前
// 未完成的请求
onCleanup(cancel)
data.value = await response
})
停止侦听器:
const stop = watchEffect(() => {})
// 当不再需要此侦听器时:
stop()
暂停/恢复侦听器:
const { stop, pause, resume } = watchEffect(() => {})
// 暂停侦听器
pause()
// 稍后恢复
resume()
// 停止
stop()
副作用清理:
watchEffect(async (onCleanup) => {
const { response, cancel } = doAsyncWork(newId)
// 如果 `id` 变化,则调用 `cancel`,
// 如果之前的请求未完成,则取消该请求
onCleanup(cancel)
data.value = await response
})
3.5+ 中的副作用清理:
import { onWatcherCleanup } from 'vue'
watchEffect(async () => {
const { response, cancel } = doAsyncWork(newId)
// 如果 `id` 变化,则调用 `cancel`,
// 如果之前的请求未完成,则取消该请求
onWatcherCleanup(cancel)
data.value = await response
})
选项:
watchEffect(() => {}, {
flush: 'post',
onTrack(e) {
debugger
},
onTrigger(e) {
debugger
}
})
watchPostEffect()
watchEffect() 使用 flush: 'post'
选项时的别名。
watchSyncEffect()
watchEffect() 使用 flush: 'sync'
选项时的别名。
watch()
侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。
类型
// 侦听单个来源
function watch<T>(
source: WatchSource<T>,
callback: WatchCallback<T>,
options?: WatchOptions
): WatchHandle
// 侦听多个来源
function watch<T>(
sources: WatchSource<T>[],
callback: WatchCallback<T[]>,
options?: WatchOptions
): WatchHandle
type WatchCallback<T> = (
value: T,
oldValue: T,
onCleanup: (cleanupFn: () => void) => void
) => void
type WatchSource<T> =
| Ref<T> // ref
| (() => T) // getter
| T extends object
? T
: never // 响应式对象
interface WatchOptions extends WatchEffectOptions {
immediate?: boolean // 默认:false
deep?: boolean | number // 默认:false
flush?: 'pre' | 'post' | 'sync' // 默认:'pre'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
once?: boolean // 默认:false (3.4+)
}
interface WatchHandle {
(): void // 可调用,与 `stop` 相同
pause: () => void
resume: () => void
stop: () => void
}
为了便于阅读,对类型进行了简化
-
详细信息
watch()
默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。第一个参数是侦听器的源。这个来源可以是以下几种:
第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。
当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。
第三个可选的参数是一个对象,支持以下这些选项:
与 watchEffect() 相比,
watch()
使我们可以:- 一个函数,返回一个值
- 一个 ref
- 一个响应式对象
- ...或是由以上类型的值组成的数组
immediate
:在侦听器创建时立即触发回调。第一次调用时旧值是undefined
。deep
:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。在 3.5+ 中,此参数还可以是指示最大遍历深度的数字。参考深层侦听器。flush
:调整回调函数的刷新时机。参考回调的刷新时机及 watchEffect()。onTrack / onTrigger
:调试侦听器的依赖。参考调试侦听器。once
:(3.4+) 回调函数只会运行一次。侦听器将在回调函数首次运行后自动停止。- 懒执行副作用;
- 更加明确是应该由哪个状态触发侦听器重新执行;
- 可以访问所侦听状态的前一个值和当前值。
-
示例
侦听一个 getter 函数:
jsconst state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { /* ... */ } )
侦听一个 ref:
jsconst count = ref(0) watch(count, (count, prevCount) => { /* ... */ })
当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值:
jswatch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })
当使用 getter 函数作为源时,回调只在此函数的返回值变化时才会触发。如果你想让回调在深层级变更时也能触发,你需要使用
js{ deep: true }
强制侦听器进入深层级模式。在深层级模式时,如果回调函数由于深层级的变更而被触发,那么新值和旧值将是同一个对象。const state = reactive({ count: 0 }) watch( () => state, (newValue, oldValue) => { // newValue === oldValue }, { deep: true } )
当直接侦听一个响应式对象时,侦听器会自动启用深层模式:
jsconst state = reactive({ count: 0 }) watch(state, () => { /* 深层级变更状态所触发的回调 */ })
jswatch()
和 watchEffect() 享有相同的刷新时机和调试选项:watch(source, callback, { flush: 'post', onTrack(e) { debugger }, onTrigger(e) { debugger } })
停止侦听器:
jsconst stop = watch(source, callback) // 当已不再需要该侦听器时: stop()
暂停/恢复侦听器:
jsconst { stop, pause, resume } = watchEffect(() => {}) // 暂停侦听器 pause() // 稍后恢复 resume() // 停止 stop()
副作用清理:
jswatch(id, async (newId, oldId, onCleanup) => { const { response, cancel } = doAsyncWork(newId) // 当 `id` 变化时,`cancel` 将被调用, // 取消之前的未完成的请求 onCleanup(cancel) data.value = await response })
3.5+ 中的副作用清理:
jsimport { onWatcherCleanup } from 'vue' watch(id, async (newId) => { const { response, cancel } = doAsyncWork(newId) onWatcherCleanup(cancel) data.value = await response })
-
参考
onWatcherCleanup()
注册一个清理函数,在当前侦听器即将重新运行时执行。只能在 watchEffect
作用函数或 watch
回调函数的同步执行期间调用 (即不能在异步函数的 await
语句之后调用)。
-
类型
tsfunction onWatcherCleanup( cleanupFn: () => void, failSilently?: boolean ): void
-
示例
tsimport { watch, onWatcherCleanup } from 'vue' watch(id, (newId) => { const { response, cancel } = doAsyncWork(newId) // 如果 `id` 变化,则调用 `cancel`, // 如果之前的请求未完成,则取消该请求 onWatcherCleanup(cancel) })