Lifecycle hooks
Every component goes through stages: creation, rendering onto the page (mounting), updates and removal (unmounting). Lifecycle hooks are functions through which you ask Vue to run code at a given stage, for example to start a timer when the component appears and stop it when the component disappears.
The onMounted hook
onMounted is called when the component's elements are already in the DOM:
<!-- src/components/TodoHeader.vue -->
<script setup>
import { onMounted } from 'vue'
console.log('setup: the component is being created')
onMounted(() => {
console.log('mounted: the component is on the page')
})
</script>
<template>
<h1>My tasks</h1>
</template>The browser console shows two lines in this order: setup first, then mounted. Top-level <script setup> code runs before rendering, so there are no DOM elements there yet.
Main hooks
| Hook | When it is called | What for |
|---|---|---|
onMounted | The component is on the page | DOM work, loading data, subscriptions |
onUpdated | After a re-render caused by data changes | Rarely: reading DOM sizes |
onBeforeUnmount | Before removal | Save something while the DOM still exists |
onUnmounted | The component is removed | Stop timers, remove listeners |
All hooks are imported from vue and called synchronously in <script setup>.
A timer with cleanup
A clock in the task list header is an example that needs two hooks:
<!-- src/components/TodoClock.vue -->
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const time = ref(new Date().toLocaleTimeString())
let timerId
onMounted(() => {
timerId = setInterval(() => {
time.value = new Date().toLocaleTimeString()
}, 1000)
})
onUnmounted(() => {
clearInterval(timerId)
})
</script>
<template>
<p>The time is {{ time }}</p>
</template>Use the component in App.vue with the line <TodoClock v-if="showClock" /> — the clock ticks every second. When showClock becomes false, the component is removed and onUnmounted stops the timer.
Listeners on window
Listeners attached to window or document are removed the same way:
<script setup>
import { onMounted, onUnmounted } from 'vue'
function onKey(event) {
if (event.key === 'Escape') console.log('Close')
}
onMounted(() => window.addEventListener('keydown', onKey))
onUnmounted(() => window.removeEventListener('keydown', onKey))
</script>While the component is on the page, pressing Escape prints "Close" to the console.
Common mistake
Not stopping a timer or removing a listener in onUnmounted. The component leaves the page, but setInterval keeps running. If the component is shown and hidden several times, the timers pile up: the page slows down and the console fills with repeated messages. Whatever you start in onMounted, stop in onUnmounted.