vue3 组件实例未销毁?


<script setup>
import { useDocumentVisibility } from '@vueuse/core'
import { timeFormat } from '@/utils/time.js'
import { scrollToTop } from '@/utils/dom.js'

const visibility = useDocumentVisibility()
const searchQuery = reactive({
  page: 1,
  size: 14,
  status: '',
  account: '',
  postId: ''
})
const searchQueryFormRef = ref(null)
const state = reactive({
  pageList: []
})
const totalPage = ref(0)

let autoUpdateTimer = null
const autoUpdateCheck = ref(false)
let getListSignal = null


function clearAutoUpdate() {
  if (autoUpdateTimer) {
    clearTimeout(autoUpdateTimer)
    autoUpdateTimer = null
  }
}

function getList(goTop = false) {
  // if (getListSignal) {
  //   getListSignal.abort()
  // }
  // getListSignal = new AbortController()
  window.aaa += 1
  console.log('window.aaa', window.aaa)
  api.queueList(toRaw(searchQuery), {
    // signal: getListSignal.signal
  }).then((res) => {
    window.aaa -= 1
    console.log(res.data.data[0])
    state.pageList = res.data.data
    totalPage.value = res.data.totalPage
    console.log('autoUpdateCheck.value', autoUpdateCheck.value)
    console.log('visibility.value', visibility.value)
    if (autoUpdateCheck.value && visibility.value === 'visible') {
      autoUpdateTimer = setTimeout(() => {
        getList()
      }, 1000)
    }
    goTop && scrollToTop()
  })
}

watch(visibility, (current) => {
  console.log('current', current)
  console.log('autoUpdateCheck.value', autoUpdateCheck.value)
  console.log('visibility.value', visibility.value)
  if (current === 'visible') {
    if (autoUpdateCheck.value) {
      getList()
    }
  } else {
    clearAutoUpdate()
  }
})

function searchList() {
  searchQuery.page = 1
  getList(true)
}

function paginationChange(val) {
  console.log(val)
  searchQuery.page = val
  getList(true)
}

function resetSearchForm() {
  searchQueryFormRef.value.reset()
  searchList()
}

searchList()

function autoUpdateChange(e) {
  console.log(e)
  if (e) {
    getList()
  } else {
    clearAutoUpdate()
  }
}



onMounted(() => {
  console.log('onMounted')
})
onActivated(() => {
  console.log('onActivated')
})
onDeactivated(() => {
  console.log('onDeactivated')
})
onBeforeUnmount(() => {
  console.log('onBeforeUnmount')
  clearAutoUpdate()
})
onUnmounted(() => {
  clearAutoUpdate()
  console.log('onUnmounted')
})
</script>

vue3
接口pending 的时候,切换路由,理论当前实例会被销毁,autoUpdate 变量 和 visible 变量都不存在了,但是打印出来仍然存在。导致离开页面了,定时器还在执行。

关键点在,路由已经切换了 if (autoUpdateCheck.value && visibility.value === 'visible') 这个条件依然成立,导致定时器执行

1.组件实例为什么没有销毁

生命周期都正常执行。
页面没有keep-alive

阅读 1.4k
avatarAI BotBETA

Vue 3 的组件实例在路由切换时确实应该被销毁,如果你遇到组件实例未销毁的问题,可能有几个原因:

  1. 路由配置问题
    确保你的路由配置中没有错误,尤其是没有错误地使用了 keep-alive 或者其他可能导致组件缓存的配置。
  2. 异步操作管理
    在 Vue 组件中,如果你有异步操作(如 API 调用、定时器、订阅事件等),你需要在组件卸载时正确地清理它们。在你的代码中,autoUpdateTimer 应该在组件卸载时清除,但你也要确保 getList 函数内部没有创建其他可能导致组件保持活动状态的异步操作。
  3. Vue 的响应式系统
    Vue 的响应式系统可能在你预期组件销毁之后仍然保持一些变量的活性。即使组件实例被销毁,Vue 的响应式系统仍然可能保留对变量的引用,直到没有任何活跃组件或实例引用它们。在你的例子中,autoUpdateCheckvisibility 可能是响应式引用,即使组件被销毁,它们也可能继续存在,直到没有其他活动组件引用它们。
  4. 控制台日志输出
    如果你在控制台看到变量仍然存在的日志输出,这可能是因为日志是在组件卸载之后异步执行的。即使组件实例已经被销毁,但异步回调(如 API 调用的 .then)可能仍然在队列中等待执行,因此当它们最终执行时,它们可能会输出到控制台。
  5. Vue 开发者工具
    如果你在使用 Vue Devtools,它可能会保留一些组件状态的信息,即使组件已经被销毁。这是为了帮助你调试,并不意味着组件实例实际上仍然存在。

为了解决这个问题,你可以尝试以下几个步骤:

  • 确保路由配置没有错误,并且没有使用 keep-alive
  • onBeforeUnmountonUnmounted 生命周期钩子中清理所有异步操作和定时器。
  • 检查组件中是否还有其他可能导致组件保持活动状态的异步操作或订阅事件。
  • 确保你没有在其他地方(如全局状态管理、事件总线等)保留对组件实例或其属性的引用。

最后,如果你确认组件实例没有被正确销毁,并且这导致了问题(如定时器继续运行),那么你可能需要进一步调查你的应用代码和 Vue 的使用方式,以找出为什么组件实例没有被销毁的原因。

1 个回答
  • 你还在用的变量都不会销毁,即使只是console.log。
  • 定时器需要手动销毁,如果嫌麻烦,可以自定义一个hook,比如 useMyInterval
  • 即使定时器销毁了,但你的网络请求依然在执行,也只能手动abort请求或者组件销毁后判断以下,不执行请求回调里的操作
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题