Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/cleanup-side-effects.md
1---2title: Clean Up Event Listeners and Intervals in onUnmounted3impact: HIGH4impactDescription: Failing to clean up side effects causes memory leaks and ghost event handlers5type: capability6tags: [vue3, lifecycle, memory-leak, event-listeners, intervals, cleanup]7---89# Clean Up Event Listeners and Intervals in onUnmounted1011**Impact: HIGH** - Failing to clean up event listeners, intervals, timeouts, and subscriptions when a component unmounts causes memory leaks and ghost handlers that continue running, leading to performance degradation and subtle bugs in Single Page Applications.1213When using custom events, timers, WebSocket connections, or third-party libraries, always clean up in `onUnmounted` (Composition API) or `unmounted` (Options API).1415## Task Checklist1617- [ ] Track all addEventListener calls and remove them in onUnmounted18- [ ] Clear all setInterval and setTimeout calls in onUnmounted19- [ ] Unsubscribe from external event emitters and observables20- [ ] Disconnect WebSocket connections and third-party library instances21- [ ] Use `onBeforeUnmount` if cleanup must happen before DOM removal2223**Incorrect:**24```javascript25// Composition API - WRONG: No cleanup26import { onMounted } from 'vue'2728export default {29setup() {30onMounted(() => {31// These keep running after component unmounts!32window.addEventListener('resize', handleResize)33setInterval(pollServer, 5000)34socket.on('message', handleMessage)35})36}37}38```3940```javascript41// Options API - WRONG: No cleanup42export default {43mounted() {44window.addEventListener('scroll', this.handleScroll)45this.timer = setInterval(this.refresh, 10000)46}47// Component unmounts, but listeners and timers persist!48}49```5051**Correct:**52```javascript53// Composition API - CORRECT: Proper cleanup54import { onMounted, onUnmounted, ref } from 'vue'5556export default {57setup() {58const intervalId = ref(null)5960const handleResize = () => {61// handle resize62}6364const handleMessage = (msg) => {65// handle message66}6768onMounted(() => {69window.addEventListener('resize', handleResize)70intervalId.value = setInterval(pollServer, 5000)71socket.on('message', handleMessage)72})7374onUnmounted(() => {75// Clean up everything!76window.removeEventListener('resize', handleResize)7778if (intervalId.value) {79clearInterval(intervalId.value)80}8182socket.off('message', handleMessage)83})84}85}86```8788```javascript89// Options API - CORRECT: Proper cleanup90export default {91data() {92return {93timer: null94}95},96mounted() {97window.addEventListener('scroll', this.handleScroll)98this.timer = setInterval(this.refresh, 10000)99},100unmounted() {101window.removeEventListener('scroll', this.handleScroll)102if (this.timer) {103clearInterval(this.timer)104}105},106methods: {107handleScroll() { /* ... */ },108refresh() { /* ... */ }109}110}111```112113## Using Composable Pattern for Auto-Cleanup114115```javascript116// Reusable composable with automatic cleanup117import { onMounted, onUnmounted } from 'vue'118119export function useEventListener(target, event, handler) {120onMounted(() => {121target.addEventListener(event, handler)122})123124onUnmounted(() => {125target.removeEventListener(event, handler)126})127}128129export function useInterval(callback, delay) {130let intervalId = null131132onMounted(() => {133intervalId = setInterval(callback, delay)134})135136onUnmounted(() => {137if (intervalId) clearInterval(intervalId)138})139}140141// Usage - cleanup is automatic142import { useEventListener, useInterval } from './composables'143144export default {145setup() {146useEventListener(window, 'resize', handleResize)147useInterval(pollServer, 5000)148// No manual cleanup needed!149}150}151```152153## VueUse Alternative154155```javascript156// VueUse provides cleanup-aware composables157import { useEventListener, useIntervalFn } from '@vueuse/core'158159export default {160setup() {161// Automatically cleaned up on unmount162useEventListener(window, 'resize', handleResize)163164const { pause, resume } = useIntervalFn(pollServer, 5000)165// Also provides pause/resume controls166}167}168```169170## Reference171- [Vue.js Lifecycle Hooks](https://vuejs.org/guide/essentials/lifecycle.html)172- [VueUse - useEventListener](https://vueuse.org/core/useEventListener/)173