Every Vue component instance goes through a series of initialization steps. During these steps, lifecycle hooks are called, allowing you to add your own code.
From packages/runtime-core/src/apiLifecycle.ts:85, called right before the component is mounted:
<script setup>import { ref, onBeforeMount } from 'vue'const data = ref(null)onBeforeMount(() => { console.log('Component is about to mount') // Component is not yet in the DOM // Refs are not yet available})</script>
At this stage, the component has finished setting up its reactive state, but no DOM nodes have been created yet.
From packages/runtime-core/src/apiLifecycle.ts:86, called after the component is mounted:
<template> <div ref="el">Hello</div></template><script setup>import { ref, onMounted } from 'vue'const el = ref(null)onMounted(() => { console.log('Component is mounted') console.log(el.value) // Access DOM element // Good time for: // - DOM manipulations // - Integrating third-party libraries // - Fetching data // - Setting up event listeners})</script>
onMounted is the most commonly used lifecycle hook. Use it to access DOM elements, start timers, or make API calls.
From packages/runtime-core/src/apiLifecycle.ts:87-89, called before the component re-renders:
<script setup>import { ref, onBeforeUpdate } from 'vue'const count = ref(0)onBeforeUpdate(() => { console.log('Before update:', count.value) // Access state before it's applied to the DOM})</script>
Don’t mutate component state in onBeforeUpdate as it can cause infinite update loops.
From packages/runtime-core/src/apiLifecycle.ts:90, called after the component has updated its DOM tree:
<template> <div ref="el">{{ count }}</div> <button @click="count++">Increment</button></template><script setup>import { ref, onUpdated } from 'vue'const count = ref(0)const el = ref(null)onUpdated(() => { console.log('Component updated') console.log('DOM content:', el.value.textContent) // DOM has been updated})</script>
onUpdated is called after any DOM update, which can be triggered by different state changes. Use a watcher if you need to react to specific state changes.
From packages/runtime-core/src/apiLifecycle.ts:91-93, called before the component is unmounted:
<script setup>import { onMounted, onBeforeUnmount } from 'vue'let interval = nullonMounted(() => { interval = setInterval(() => { console.log('Tick') }, 1000)})onBeforeUnmount(() => { console.log('Component is about to be unmounted') // Component is still fully functional if (interval) { clearInterval(interval) }})</script>
From packages/runtime-core/src/apiLifecycle.ts:95-97, called during server-side rendering:
<script setup>import { ref, onServerPrefetch } from 'vue'const data = ref(null)onServerPrefetch(async () => { // Fetch data on the server data.value = await fetchData()})</script>
onServerPrefetch is only called during SSR. It allows you to fetch data on the server before rendering.
From packages/runtime-core/src/components/KeepAlive.ts, used with <KeepAlive> components:
<script setup>import { onActivated, onDeactivated } from 'vue'onActivated(() => { console.log('Component activated') // Called when component is re-activated from cache})onDeactivated(() => { console.log('Component deactivated') // Called when component is cached by <KeepAlive>})</script>
<template> <div ref="root"> <h1>{{ title }}</h1> <p>Count: {{ count }}</p> <button @click="count++">Increment</button> </div></template><script setup>import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue'const title = ref('Lifecycle Demo')const count = ref(0)const root = ref(null)// Before mountonBeforeMount(() => { console.log('1. Before Mount') console.log(' - Reactive state is ready') console.log(' - DOM not yet created')})// MountedonMounted(() => { console.log('2. Mounted') console.log(' - Component in DOM') console.log(' - Can access refs:', root.value) // Setup: timers, event listeners, etc. const timer = setInterval(() => { console.log('Timer tick') }, 5000) // Cleanup on unmount onUnmounted(() => { clearInterval(timer) })})// Before updateonBeforeUpdate(() => { console.log('3. Before Update') console.log(' - State changed but DOM not yet updated') console.log(' - Current count:', count.value)})// UpdatedonUpdated(() => { console.log('4. Updated') console.log(' - DOM has been updated') console.log(' - New DOM content:', root.value?.textContent)})// Before unmountonBeforeUnmount(() => { console.log('5. Before Unmount') console.log(' - Component still functional') console.log(' - Good time to cleanup')})// UnmountedonUnmounted(() => { console.log('6. Unmounted') console.log(' - Component removed from DOM') console.log(' - Final cleanup')})</script>