Introduction to Vue Lifecycle Hooks

Master the art of controlling Vue component behavior at every stage of its existence

What Are Vue Lifecycle Hooks?

Lifecycle hooks are functions that Vue calls at specific stages during a component's lifecycle. When a Vue component instance is created, it follows a series of initialization steps: setting up data observation, compiling the template, mounting to the DOM, updating the DOM as data changes, and unmounting. During this process, Vue invokes lifecycle hooks, allowing developers to run custom code at specific stages.

Understanding these stages is key to grasping the Vue reactivity system and managing component behavior effectively. For teams building professional web applications, mastering lifecycle hooks is essential for creating robust, maintainable codebases.

The Four Lifecycle Phases

Vue components go through four main lifecycle phases:

  1. Creation Phase - Initial setup and initialization
  2. Mounting Phase - Component is rendered and added to the DOM
  3. Updating Phase - Component re-renders due to data changes
  4. Unmounting Phase - Component is removed from the DOM

Each phase has hooks that let you execute code at precise moments during the component's lifecycle.

The Creation Phase

The creation phase is the initial stage of a Vue component lifecycle. This phase lays the groundwork for everything that follows. During this phase, Vue begins constructing the component instance before it is added to the DOM.

The setup() Hook

The setup() hook serves as the entry point for Composition API usage. It is the first lifecycle hook called in Vue, triggered immediately after the application instance is initialized. In the Composition API, the setup() hook replaces the beforeCreate() and created() hooks from the Options API.

import { ref } from 'vue'

export default {
 setup() {
 const count = ref(0)
 console.log('Setup has been called')
 return { count }
 }
}

When using TypeScript with Vue, the Composition API provides superior type inference compared to the Options API--making it the recommended approach for TypeScript projects.

The Mounting Phase

The mounting phase marks the moment your Vue component renders for the first time and is inserted into the DOM. These hooks don't run during server-side rendering since the server doesn't have access to a real DOM.

onBeforeMount()

Called after Vue runs the setup() hook but before the DOM is created. At this point, reactive state is initialized but DOM elements aren't available yet.

onMounted()

Called after the component has been mounted to the DOM. This is the ideal place for DOM access, event listeners, and initial data fetching.

import { onBeforeMount, onMounted } from 'vue'

onBeforeMount(() => {
 console.log('About to mount - DOM not ready')
})

onMounted(() => {
 console.log('Component is mounted - DOM is accessible')
 // Safe to access DOM elements here
})

The Updating Phase

The updating phase is triggered whenever the component's reactive data changes. Vue automatically re-renders the affected parts of the DOM using its virtual DOM diffing algorithm.

onBeforeUpdate()

Called right before a component is about to update its DOM tree due to a reactive state change. Use this to capture the DOM state before changes.

onUpdated()

Called after the component has re-rendered. The DOM now reflects the new state. Important: Avoid mutating state here to prevent infinite update loops.

import { onBeforeUpdate, onUpdated } from 'vue'

const count = ref(0)

onBeforeUpdate(() => {
 console.log('About to update - DOM still has old values')
})

onUpdated(() => {
 console.log('Component has been updated with new values')
})

The Unmounting Phase

The unmounting phase marks the final stage in a Vue component's lifecycle. Vue actively cleans up the component to free memory and prevent memory leaks.

onBeforeUnmount()

Called right before the component is unmounted. This is your final opportunity to run cleanup logic while the component instance is still accessible.

onUnmounted()

Called after the component has been fully removed from the DOM. Use this for final cleanup of side effects.

import { onBeforeUnmount, onUnmounted } from 'vue'

onBeforeUnmount(() => {
 console.log('About to unmount - component still accessible')
 // Final preparation before removal
})

onUnmounted(() => {
 console.log('Component has been unmounted')
 // Clean up timers, event listeners, subscriptions
})

Additional Lifecycle Hooks in Vue 3

Vue 3 introduces several additional hooks for advanced use cases:

Debug Hooks

  • onRenderTracked() - Called when a reactive dependency is tracked during render (development only)
  • onRenderTriggered() - Called when a reactive dependency triggers a re-render (development only)

KeepAlive Hooks

  • onActivated() - Called when a cached component is activated
  • onDeactivated() - Called when a cached component is deactivated

Error Handling

  • onErrorCaptured() - Catches errors in child components

SSR

  • onServerPrefetch() - Async data fetching before SSR rendering
import { onRenderTracked, onRenderTriggered, onErrorCaptured } from 'vue'

onRenderTracked((event) => {
 console.log('Tracked:', event)
})

onRenderTriggered((event) => {
 console.log('Triggered by:', event)
})

onErrorCaptured((err) => {
 console.error('Error captured:', err)
})

Best Practices for Lifecycle Hooks

1. Organize Hooks Clearly

Group related hooks together. If you add an event listener in onMounted(), clean it up in onUnmounted() right afterward.

2. Avoid Heavy Operations

Don't execute large computations or intense loops in onMounted() or onUpdated()--these can block the main thread.

3. Always Perform Cleanup

Clean up intervals, timeouts, event listeners, and subscriptions in unmounting hooks to prevent memory leaks:

let timer

onMounted(() => {
 timer = setInterval(() => {
 // Periodic task
 }, 1000)
})

onUnmounted(() => {
 clearInterval(timer)
})

4. Keep Logic Declarative

Use computed() and watch() instead of manually managing state in lifecycle hooks.

5. Don't Use Arrow Functions

Arrow functions lose access to the component instance via this.

Performance Considerations

Minimizing onMounted Work

onMounted() delays user interactivity if it contains heavy operations. Consider lazy-loading non-critical resources.

Efficient Updates

onBeforeUpdate() and onUpdated() run on every update cycle. Use debouncing or move expensive logic to computed properties that only run when specific dependencies change.

Memory Leak Prevention

The unmounting phase is critical for preventing memory leaks. Any subscription, timer, or event listener created during the component's lifetime must be cleaned up.

Key Takeaway

The true power of lifecycle hooks lies in how well you organize, optimize, and clean up your logic within them--directly impacting your application's performance and maintainability.

Common Mistakes to Avoid

MistakeWhy It's ProblematicSolution
Using arrow functionsLoses access to component instanceUse regular function declarations
Forgetting cleanupCauses memory leaksAlways clean up in unmounting hooks
Mutating state in onUpdatedCauses infinite update loopsUse watchers instead
DOM access in onBeforeMountElement not available yetUse onMounted() for DOM access
Async operations without cleanupRace conditions and memory leaksTrack and cancel in unmount hooks
Heavy computations in hooksBlocks main threadMove to computed/watchers
Multiple subscriptions without trackingHard to clean up properlyUse a subscription map or composables

Composition API vs Options API

Options API:

export default {
 mounted() {
 console.log('mounted')
 }
}

Composition API (recommended):

<script setup>
import { onMounted } from 'vue'

onMounted(() => {
 console.log('mounted')
})
</script>

The Composition API approach offers better code organization, easier logic reuse through composables, and improved TypeScript support. This modern pattern is also explored in our guide to CSS Modules for component-scoped styling.

Conclusion

Lifecycle hooks are your window into how Vue operates behind the scenes. Whether you're building a simple component or architecting complex dynamic interfaces, understanding these hooks helps you write cleaner, more maintainable Vue applications.

Master these concepts, and you'll have the tools to build robust, efficient Vue applications that stand the test of time. The Composition API approach provides a more flexible and scalable foundation for building modern web applications.


Sources:

  1. Vue.js Official Documentation - Lifecycle Hooks
  2. Telerik: Vue Basics: Mastering Vue Lifecycle Hooks
  3. LogRocket: Introduction to Vue Lifecycle Hooks