Resolving Vue 3 Lifecycle Injection Warnings in Async Contexts

When working with Vue 3's Composition API, you might encounter the following console warning:

[Vue warn]: onUnmounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.

This warning indicates that a lifecycle injection API was invoked outside the synchronous execution phase of the setup() function. Hooks like onUnmounted and onMounted depend on an active component instance context to bind their callbacks. This context is strictly available only during the synchronous portion of setup().

If an asynchronous operation (such as an await) is executed inside setup, or within an asynchronous onMounted callback, the synchronous setup context is already destroyed once execution resumes. Any attempt to register a lifecycle hook after this point will fail and produce the warning.

The getCurrentInstance() function can be used to verify the current context. However, it is essential to understand its behavior:

  • getCurrentInstance() === null does not mean the component has been unmounted or destroyed.
  • It merely signals that the current execution flow is outside the synchronous setup() scope.
  • Even when a component is fully active and rendered, calling getCurrentInstance() inside a delayed callback or after an await will return null.

The following example demonstrates a typical scenario where this warning is triggered:

<script setup>
import { onMounted, onUnmounted, getCurrentInstance } from 'vue'

// Synchronous context is active here
const syncInstance = getCurrentInstance()
console.log('Synchronous setup phase - Instance:', syncInstance)

const requestRemoteConfig = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('Remote configuration fetched')
      resolve({ theme: 'dark' })
    }, 1000)
  })
}

const bindCleanupLogic = () => {
  const currentContext = getCurrentInstance()
  console.log('After await - Instance:', currentContext) // Evaluates to null
  
  onUnmounted(() => {
    console.log('Unmounted callback triggered') // Triggers the Vue warning
  })
}

onMounted(async () => {
  console.log('Mounted hook initiated')
  
  await requestRemoteConfig()
  
  // Context is lost after the await expression
  bindCleanupLogic() 
})
</script>

In this component, the await requestRemoteConfig() pauses the execution thread. When the Promise resolves and bindCleanupLogic() is invoked, the synchronous setup scope has already concluded. Therefore, the onUnmounted registrasion fails to associate with the component instance.

Tags: vue3 Composition API lifecycle hooks getCurrentInstance async setup

Posted on Thu, 14 May 2026 00:42:15 +0000 by Stinger51