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() === nulldoes 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 anawaitwill returnnull.
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.