副作用清理 onWatcherCleanup

37ebcf612b712a5adcd874fc34168d7b.png

有时我们可能会在侦听器中执行副作用,例如异步请求:

watch(id, (newId) => {  fetch(`/api/${newId}`).then(() => {    // 回调逻辑  })})

但是如果在请求完成之前 id 发生了变化怎么办?当上一个请求完成时,它仍会使用已经过时的 ID 值触发回调。理想情况下,我们希望能够在 id 变为新值时取消过时的请求。

我们可以使用 onWatcherCleanup() API 来注册一个清理函数,当侦听器失效并准备重新运行时会被调用:

import { watch, onWatcherCleanup } from 'vue'
watch(id, (newId) => {  const controller = new AbortController()
  fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {    // 回调逻辑  })
  onWatcherCleanup(() => {    // 终止过期请求    controller.abort()  })})

请注意,onWatcherCleanup 仅在 Vue 3.5+ 中支持,并且必须在 watchEffect 效果函数或 watch 回调函数的同步执行期间调用:你不能在异步函数的 await 语句之后调用它。

作为替代,onCleanup 函数还作为第三个参数传递给侦听器回调,以及 watchEffect 作用函数的第一个参数:

watch(id, (newId, oldId, onCleanup) => {  // ...  onCleanup(() => {    // 清理逻辑  })})
watchEffect((onCleanup) => {  // ...  onCleanup(() => {    // 清理逻辑  })})

这在 3.5 之前的版本有效。此外,通过函数参数传递的 onCleanup 与侦听器实例相绑定,因此不受 onWatcherCleanup 的同步限制。

总结

Vue 3.5+ 中支持 onWatcherCleanup() 注册一个清理函数,在当前侦听器即将重新运行时执行。只能在 watchEffect 作用函数或 watch 回调函数的同步执行期间调用 (即不能在异步函数的 await 语句之后调用)。

停止侦听器:

const stop = watch(source, callback)
// 当已不再需要该侦听器时:stop()

暂停/恢复侦听器:

const { stop, pause, resume } = watch(() => {})
// 暂停侦听器pause()
// 稍后恢复resume()
// 停止stop()

3.5+ 中的副作用清理:

import { onWatcherCleanup } from 'vue'
watch(id, async (newId) => {  const { response, cancel } = doAsyncWork(newId)  onWatcherCleanup(cancel)  data.value = await response})

在 setup() 或 <script setup> 中用同步语句创建的侦听器,会自动绑定到宿主组件实例上,并且会在宿主组件卸载时自动停止。因此,在大多数情况下,你无需关心怎么停止一个侦听器。

一个关键点是,侦听器必须用同步语句创建:如果用异步回调创建一个侦听器,那么它不会绑定到当前组件上,你必须手动停止它,以防内存泄漏。如下方这个例子:

<script setup>import { watchEffect } from 'vue'
// 它会自动停止watchEffect(() => {})
// ...这个则不会!setTimeout(() => {  watchEffect(() => {})}, 100)</script>

要手动停止一个侦听器,请调用 watch 或 watchEffect 返回的函数:

const unwatch = watchEffect(() => {})
// ...当该侦听器不再需要时unwatch()

注意,需要异步创建侦听器的情况很少,请尽可能选择同步创建。如果需要等待一些异步数据,你可以使用条件式的侦听逻辑:

// 需要异步请求得到的数据const data = ref(null)
watchEffect(() => {  if (data.value) {    // 数据加载后执行某些操作...  }})

每当被侦听源发生变化时,侦听器的回调就会执行。如果希望回调只在源变化时触发一次,请使用 once: true 选项。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值