Lifecycle Hooks
A Vue component goes through lifecycle stages — setup, mount, update, unmount. Composition API exposes them as onMounted, onUpdated, onBeforeUnmount. Use for non-reactive side effects.
Hooks + suspense + keep-alive
EXAMPLE
<script setup>
import {
onBeforeMount, onMounted, onBeforeUpdate, onUpdated,
onBeforeUnmount, onUnmounted,
onErrorCaptured, onRenderTracked, onRenderTriggered,
onActivated, onDeactivated,
ref, watchEffect,
} from 'vue';
const el = ref(null);
const online = ref(navigator.onLine);
// 1) Mount — DOM is ready
onMounted(() => {
el.value.focus();
const onChange = () => online.value = navigator.onLine;
window.addEventListener('online', onChange);
window.addEventListener('offline', onChange);
});
// 2) Cleanup
onBeforeUnmount(() => {
// remove the listeners
});
// Or use watchEffect with onCleanup for self-contained subscriptions
import { watchEffect } from 'vue';
watchEffect((onCleanup) => {
const t = setInterval(() => poll(), 5000);
onCleanup(() => clearInterval(t));
});
// 3) Update hooks — runs after every reactive update
onUpdated(() => {
// DOM has just been rerendered. Avoid setting state here (loops!)
});
// 4) Catch errors from descendant components
onErrorCaptured((err, instance, info) => {
console.error('caught from child:', err, info);
return false; // prevent propagation
});
// 5) Lifecycle hooks in plain JS modules (composables)
// composables/useMouse.js
import { ref, onMounted, onUnmounted } from 'vue';
export function useMouse() {
const x = ref(0), y = ref(0);
const update = (e) => { x.value = e.clientX; y.value = e.clientY; };
onMounted(() => window.addEventListener('mousemove', update));
onUnmounted(() => window.removeEventListener('mousemove', update));
return { x, y };
}
// 6) onActivated / onDeactivated — only inside <keep-alive>
onActivated(() => console.log('cached component shown'));
onDeactivated(() => console.log('cached component hidden'));
</script>
<template>
<input ref="el" :placeholder="online ? 'online' : 'offline'" />
</template>
<!-- 7) Full lifecycle order (Composition API) -->
<!--
setup() — script setup runs first
onBeforeMount() — about to mount
onMounted() — DOM mounted
onBeforeUpdate() / onUpdated() — reactive update
onBeforeUnmount() / onUnmounted() — teardown
onErrorCaptured() — child error
onActivated() / onDeactivated() — keep-alive only
-->
<!-- 8) Options API equivalents (older syntax, still supported) -->
<!--
export default {
mounted() { ... },
beforeUnmount() { ... },
updated() { ... },
errorCaptured() { ... },
};
-->
<!-- 9) Suspense — async setup + loading state -->
<!-- Parent -->
<Suspense>
<template #default>
<UserProfile :user-id="id" />
</template>
<template #fallback>
<Spinner />
</template>
</Suspense>
<!-- UserProfile.vue uses top-level await in setup -->
<!--
<script setup>
const { data: user } = await useFetch(`/api/users/${props.userId}`);
</script>
-->
<!-- 10) keep-alive — cache components, preserve state on switch -->
<KeepAlive :include="['Inbox', 'Profile']" :max="5">
<component :is="currentTab" />
</KeepAlive>
<!-- 11) Real patterns -->
<!-- a) Auto-focus on mount -->
<input ref="input" />
<!-- onMounted(() => input.value.focus()); -->
<!-- b) Fetch + cleanup -->
<!--
const posts = ref([]);
let abort;
onMounted(async () => {
abort = new AbortController();
posts.value = await (await fetch('/api/posts', { signal: abort.signal })).json();
});
onBeforeUnmount(() => abort?.abort());
-->
<!-- c) Subscribe to a store / event bus -->
<!--
const unsub = bus.on('refresh', refresh);
onBeforeUnmount(unsub);
-->
<!-- 12) Common bugs -->
<!--
• Forgetting to unsubscribe in onBeforeUnmount → memory leaks
• Setting reactive state in onUpdated → infinite update loop
• Doing async work in setup without try/catch — unhandled rejection
• Accessing template refs in setup() top-level — they're null until mount
• Mixing options and composition styles in the same component (works, but confusing)
-->
Why it matters
Reach for watchEffect with onCleanup for any subscription — it’s self-contained and survives reactivity changes. onMounted is for one-shot DOM work; onUnmounted for any leftovers watchEffect didn’t cover.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
onBeforeMount / onMounted / onBeforeUpdate / onUpdated / onBeforeUnmount / onUnmountedTry it Yourself »
Discussion
Loading…