官方文档:cn.vuejs.org/api/reactiv…
也就是说当使用他们两个时候,使用完成之后要及时停止他们,防止一直在运行,停止他们之后,也可以再次开启。
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
}
})
-
参考
<ul> <li><a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="指南 - 侦听器" href="https://cn.vuejs.org/guide/essentials/watchers.html#watcheffect" title="指南 - 侦听器">指南 - 侦听器</a></li> <li><a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="指南 - 侦听器调试" href="https://cn.vuejs.org/guide/extras/reactivity-in-depth.html#watcher-debugging" title="指南 - 侦听器调试">指南 - 侦听器调试</a></li> </ul> </li>
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
}
为了便于阅读,对类型进行了简化
-
详细信息
<p><code>watch()</code> 默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。</p> <p>第一个参数是侦听器的<strong>源</strong>。这个来源可以是以下几种:</p> <p>第二个参数是在发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。</p> <p>当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。</p> <p>第三个可选的参数是一个对象,支持以下这些选项:</p> <p>与 <a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="watchEffect()" href="https://cn.vuejs.org/api/reactivity-core.html#watcheffect" title="watchEffect()">watchEffect()</a> 相比,<code>watch()</code> 使我们可以:</p> <ul> <li>一个函数,返回一个值</li> <li>一个 ref</li> <li>一个响应式对象</li> <li>...或是由以上类型的值组成的数组</li> <li><strong><code>immediate</code></strong>:在侦听器创建时立即触发回调。第一次调用时旧值是 <code>undefined</code>。</li> <li><strong><code>deep</code></strong>:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。在 3.5+ 中,此参数还可以是指示最大遍历深度的数字。参考<a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="深层侦听器" href="https://cn.vuejs.org/guide/essentials/watchers.html#deep-watchers" title="深层侦听器">深层侦听器</a>。</li> <li><strong><code>flush</code></strong>:调整回调函数的刷新时机。参考<a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="回调的刷新时机" href="https://cn.vuejs.org/guide/essentials/watchers.html#callback-flush-timing" title="回调的刷新时机">回调的刷新时机</a>及 <a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="watchEffect()" href="https://cn.vuejs.org/api/reactivity-core.html#watcheffect" title="watchEffect()">watchEffect()</a>。</li> <li><strong><code>onTrack / onTrigger</code></strong>:调试侦听器的依赖。参考<a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="调试侦听器" href="https://cn.vuejs.org/guide/extras/reactivity-in-depth.html#watcher-debugging" title="调试侦听器">调试侦听器</a>。</li> <li><strong><code>once</code></strong>:(3.4+) 回调函数只会运行一次。侦听器将在回调函数首次运行后自动停止。</li> <li>懒执行副作用;</li> <li>更加明确是应该由哪个状态触发侦听器重新执行;</li> <li>可以访问所侦听状态的前一个值和当前值。</li> </ul> </li> <li> <p><strong>示例</strong></p> <p>侦听一个 getter 函数:</p> js <pre>const state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { /* ... */ } )<p>侦听一个 ref:</p> js <pre>const count = ref(0) watch(count, (count, prevCount) => { /* ... */ })<p>当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值:</p> js <pre>watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })<p>当使用 getter 函数作为源时,回调只在此函数的返回值变化时才会触发。如果你想让回调在深层级变更时也能触发,你需要使用 <code>{ deep: true }</code> 强制侦听器进入深层级模式。在深层级模式时,如果回调函数由于深层级的变更而被触发,那么新值和旧值将是同一个对象。</p> js <pre>const state = reactive({ count: 0 }) watch( () => state, (newValue, oldValue) => { // newValue === oldValue }, { deep: true } )<p>当直接侦听一个响应式对象时,侦听器会自动启用深层模式:</p> js <pre>const state = reactive({ count: 0 }) watch(state, () => { /* 深层级变更状态所触发的回调 */ })<p><code>watch()</code> 和 <a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="watchEffect()" href="https://cn.vuejs.org/api/reactivity-core.html#watcheffect" title="watchEffect()">watchEffect()</a> 享有相同的刷新时机和调试选项:</p> js <pre>watch(source, callback, { flush: 'post', onTrack(e) { debugger }, onTrigger(e) { debugger } })<p>停止侦听器:</p> js <pre>const stop = watch(source, callback)// 当已不再需要该侦听器时: stop()<p>暂停/恢复侦听器:</p> js <pre>const { stop, pause, resume } = watchEffect(() => {})// 暂停侦听器 pause()
// 稍后恢复 resume()
// 停止 stop()<p>副作用清理:</p> js <pre>watch(id, async (newId, oldId, onCleanup) => { const { response, cancel } = doAsyncWork(newId) // 当id变化时,cancel将被调用, // 取消之前的未完成的请求 onCleanup(cancel) data.value = await response })<p>3.5+ 中的副作用清理:</p> js <pre>import { onWatcherCleanup } from 'vue'watch(id, async (newId) => { const { response, cancel } = doAsyncWork(newId) onWatcherCleanup(cancel) data.value = await response }) -
参考
<ul> <li><a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="指南 - 侦听器" href="https://cn.vuejs.org/guide/essentials/watchers.html" title="指南 - 侦听器">指南 - 侦听器</a></li> <li><a data-link-icon="https://csdnimg.cn/release/blog_editor_html/release2.3.7/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=O83A" data-link-title="指南 - 侦听器调试" href="https://cn.vuejs.org/guide/extras/reactivity-in-depth.html#watcher-debugging" title="指南 - 侦听器调试">指南 - 侦听器调试</a></li> </ul> </li>
onWatcherCleanup()
注册一个清理函数,在当前侦听器即将重新运行时执行。只能在 watchEffect 作用函数或 watch 回调函数的同步执行期间调用 (即不能在异步函数的 await 语句之后调用)。
-
类型
ts<pre>function onWatcherCleanup( cleanupFn: () => void, failSilently?: boolean ): void -
示例
ts<pre>import { watch, onWatcherCleanup } from 'vue'watch(id, (newId) => { const { response, cancel } = doAsyncWork(newId) // 如果id变化,则调用cancel, // 如果之前的请求未完成,则取消该请求 onWatcherCleanup(cancel) })