Vue lifecycle hooks: practical guide and when to use each one
Why this matters
Understanding the component lifecycle helps you know exactly when to run each type of logic: initialization, DOM access, API synchronization, side effect cleanup, or debugging.
Core concept
A Vue 3 component goes through several phases:
- Creation
- Mounting
- Updating
- Unmounting
There are also special hooks for:
- Components cached with
<KeepAlive> - Error handling
- Reactive render debugging
- SSR (Server-Side Rendering)
In the next sections, we will see when each hook runs and what it is for, with examples.
Component creation
In this phase, Vue creates the component instance and sets up reactivity, but the DOM does not exist yet.
This is where you usually initialize state, configuration, or early requests.
beforeCreate
Runs before Vue configures reactivity.
<script>
export default {
beforeCreate() {
console.log('The component is starting')
}
}
</script>
beforeCreateis not available in Composition API, becausesetup()runs before any other hook.
created
Reactive state is already available, but the DOM still does not exist.
It is commonly used for:
- HTTP requests
- State initialization
- Business logic preparation
<script>
export default {
data() {
return {
users: []
}
},
async created() {
this.users = await fetch('/api/users').then(r => r.json())
}
}
</script>
createdis not available in Composition API, becausesetup()runs before any other hook.
setup()
It is the main entry point in Composition API.
Here you define:
- Reactive state
- Composables
- Watchers
- Initial component logic
<script setup>
import { ref } from 'vue'
const count = ref(0)
console.log('Setup executed')
</script>
setup()is not available in Options API, because it is exclusive to Composition API.
Component mounting
In this phase Vue creates and inserts the component DOM.
At this point it is safe to use:
- Browser APIs
- External libraries
- DOM manipulation
onBeforeMount / beforeMount
Runs right before inserting the DOM into the page.
It is not very common, but it can be useful for final pre-render logic.
<script setup>
import { onBeforeMount } from 'vue'
onBeforeMount(() => {
console.log('Component is about to mount')
})
</script><script>
export default {
beforeMount() {
console.log('Before mounting the component')
}
}
</script>onMounted / mounted
Runs after the component has been inserted into the DOM.
This is one of the most used hooks.
Typical uses:
- Initializing charts
- Registering listeners
- Focusing inputs
- Integrating third-party libraries
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
console.log('Component mounted in the DOM')
})
</script><script>
export default {
mounted() {
console.log('Component mounted')
}
}
</script>Component update
When reactive state changes, Vue re-renders the component.
These hooks let you react before or after the DOM changes.
onBeforeUpdate / beforeUpdate
Runs before Vue updates the DOM.
Can be used to inspect previous state.
<script setup>
import { onBeforeUpdate } from 'vue'
onBeforeUpdate(() => {
console.log('Before updating the DOM')
})
</script><script>
export default {
beforeUpdate() {
console.log('Before update')
}
}
</script>onUpdated / updated
Runs after Vue updates the DOM.
Useful when you need to measure or interact with the updated DOM.
onUpdatedshould not be used as a replacement forwatch.
<script setup>
import { onUpdated } from 'vue'
onUpdated(() => {
console.log('DOM has been updated')
})
</script><script>
export default {
updated() {
console.log('DOM updated')
}
}
</script>Component unmounting
When a component stops existing, Vue runs cleanup hooks.
This is key to avoid memory leaks.
onBeforeUnmount / beforeUnmount
Runs right before destroying the component.
<script setup>
import { onBeforeUnmount } from 'vue'
onBeforeUnmount(() => {
console.log('Component will be destroyed')
})
</script><script>
export default {
beforeUnmount() {
console.log('Before unmounting')
}
}
</script>onUnmounted / unmounted
Runs after the component has been destroyed.
Ideal for cleaning:
- Timers
- Sockets
- Event listeners
<script setup>
import { onMounted, onUnmounted } from 'vue'
let timer
onMounted(() => {
timer = setInterval(() => {
console.log('tick')
}, 1000)
})
onUnmounted(() => {
clearInterval(timer)
})
</script><script>
export default {
mounted() {
this.timer = setInterval(() => {
console.log('tick')
}, 1000)
},
unmounted() {
clearInterval(this.timer)
}
}
</script><KeepAlive> hooks
When a component is inside <KeepAlive>, it is not destroyed, it is only activated or deactivated.
onActivated / activated
Runs when the component becomes active again.
<script setup>
import { onActivated } from 'vue'
onActivated(() => {
console.log('Component activated again')
})
</script><script>
export default {
activated() {
console.log('Component activated')
}
}
</script>onDeactivated / deactivated
Runs when the component is hidden but stays in memory.
<script setup>
import { onDeactivated } from 'vue'
onDeactivated(() => {
console.log('Component deactivated')
})
</script><script>
export default {
deactivated() {
console.log('Component deactivated')
}
}
</script>Error handling
onErrorCaptured / errorCaptured
Allows capturing errors from child components.
<script setup>
import { onErrorCaptured } from 'vue'
onErrorCaptured((error) => {
console.error('Captured error:', error)
return false
})
</script><script>
export default {
errorCaptured(error) {
console.error('Captured error:', error)
return false
}
}
</script>Render debugging hooks
These hooks help understand why a component is re-rendering.
They should not be used by default in production.
onRenderTracked
Runs when Vue tracks a reactive dependency during render.
<script setup>
import { onRenderTracked } from 'vue'
onRenderTracked((event) => {
console.debug('Tracked dependency:', event.key)
})
</script><script>
export default {
renderTracked(event) {
console.debug('Tracked dependency:', event.key)
}
}
</script>onRenderTriggered
Runs when a dependency triggers a re-render.
<script setup>
import { onRenderTriggered } from 'vue'
onRenderTriggered((event) => {
console.debug('Re-render caused by:', event.key)
})
</script><script>
export default {
renderTriggered(event) {
console.debug('Re-render caused by:', event.key)
}
}
</script>SSR (Server-Side Rendering)
onServerPrefetch / serverPrefetch
Allows loading data before rendering HTML on the server.
This prevents empty screens during first render.
<script setup>
import { onServerPrefetch } from 'vue'
onServerPrefetch(async () => {
await fetch('/api/data')
})
</script><script>
export default {
async serverPrefetch() {
await fetch('/api/data')
}
}
</script>When to use hooks (and when not to)
Use them when:
- You need real DOM access (
onMounted) - You need resource cleanup (
onUnmounted) - You are working with SSR (
onServerPrefetch) - You need to react to component lifecycle phases
Avoid them when:
- A
computedsolves the problem - A
watchis enough - You only need to react to specific state changes
Hooks coordinate lifecycle moments and should not hold all component logic.
Summary
Lifecycle hooks let you control key component moments:
| Phase | Main hooks |
|---|---|
| Creation | setup, created |
| Mounting | onMounted, mounted |
| Updating | onUpdated, updated |
| Unmounting | onUnmounted, unmounted |
| Cache | onActivated, onDeactivated |
| SSR | onServerPrefetch |
If you are not sure which hook to use, ask first: At what point in the component lifecycle do I need this logic to run?
