Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Lifecycle Hooks  ›  Lesson

Updates and Cleanup

Lifecycle Hooks 13 minonUpdated runs after a re-render and onUnmounted runs when the component is removed, the place to undo anything you started.

Updates and Cleanup

Shelf gets a ReadingTimer that counts the seconds you spend on a book. It works. Then testers open and close it twenty times, and the app crawls: twenty timers are still ticking, each updating state no one can see. Vue removed the component, but not the things it started. Cleanup is your job.

The rule

Whatever you start on mount, you stop on unmount.

<!-- ReadingTimer.vue -->
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const seconds = ref(0)
let timerId

function onKey(e) {
  if (e.key === ' ') seconds.value = 0
}

onMounted(() => {
  timerId = setInterval(() => seconds.value++, 1000)
  window.addEventListener('keydown', onKey)
})

onUnmounted(() => {
  clearInterval(timerId)
  window.removeEventListener('keydown', onKey)
})
</script>

<template>
  <p>Reading for {{ seconds }} s</p>
</template>

Vue cleans up what Vue created: the component's elements, its listeners written with @, its computeds and watchers. It does not know about things you started with browser APIs: timers from setInterval or setTimeout, listeners added to window or document, open network connections, or third-party libraries attached to an element. Those need a matching stop in onUnmounted (or onBeforeUnmount, which runs a moment earlier while the DOM is still in place).

Note that the listener must be the same function in both calls. removeEventListener('keydown', (e) => ...) with a new arrow function removes nothing, because it is a different function.

Update hooks. onBeforeUpdate and onUpdated run around each re-render caused by a state change. onUpdated is the moment the DOM reflects the new state, useful for things like scrolling a chat to its newest message. Two cautions: it runs after any change in the component, and changing state inside it triggers another update, which can loop forever. Most "do something when X changes" jobs belong in a watcher instead (next lesson).

The shortcut

Use pairs. Every time you write a "start" line in onMounted, write its "stop" line in onUnmounted right away.

Pairing ReadingTimer's resourcesStep 1 of 4
  1. setInterval

    Start: timerId = setInterval(...). Stop: clearInterval(timerId).

Drills

Answer fast — trust the rule.

quick drill

A component starts setInterval in onMounted and never clears it. What happens after it is removed?

quick drill

Which of these must you clean up yourself?

quick drill

onUnmounted(() => window.removeEventListener('keydown', (e) => handle(e))) does not remove the listener. Why?

quick drill

Why is changing state inside onUpdated risky?

Remember

  • onUnmounted is where you undo timers, window listeners and outside libraries; onUpdated runs after each re-render.
  • Shortcut: write every start and stop as a pair.
  • Trap: removing a listener with a different function, and changing state in onUpdated.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainA leaking timer

A ReadingTimer component starts setInterval in onMounted to count reading seconds. Users open and close it many times and the app slows down. Explain the cause and the fix.