---
title: Simple Hash Routing Requires Event Listener Cleanup
impact: MEDIUM
impactDescription: When implementing basic routing without Vue Router, forgetting to remove hashchange listeners causes memory leaks and multiple handler execution
type: gotcha
tags: [vue3, routing, events, memory-leak, cleanup]
---
# Simple Hash Routing Requires Event Listener Cleanup
**Impact: MEDIUM** - When implementing basic client-side routing without Vue Router (using hash-based routing with `hashchange` events), you must clean up event listeners when the component unmounts. Failure to do so causes memory leaks and can result in multiple handlers firing after the component is recreated.
## Task Checklist
- [ ] Store event listener reference for cleanup
- [ ] Use onUnmounted to remove event listener
- [ ] Consider using Vue Router instead for production apps
- [ ] Test component mount/unmount cycles
## The Problem
```vue
```
**What happens:**
1. Component mounts, adds listener
2. Component unmounts (e.g., route change, v-if toggle)
3. Component mounts again, adds ANOTHER listener
4. Now TWO listeners respond to each hash change
5. Eventually causes performance issues and memory leaks
## Solution: Proper Cleanup with onUnmounted
```vue
```
## Solution: Using Options API
```vue
```
## Solution: Composable for Reusable Hash Routing
```javascript
// composables/useHashRouter.js
import { ref, computed, onUnmounted } from 'vue'
export function useHashRouter(routes, notFoundComponent = null) {
const currentPath = ref(window.location.hash)
function handleHashChange() {
currentPath.value = window.location.hash
}
// Setup
window.addEventListener('hashchange', handleHashChange)
// Cleanup - handled automatically when component unmounts
onUnmounted(() => {
window.removeEventListener('hashchange', handleHashChange)
})
const currentView = computed(() => {
const path = currentPath.value.slice(1) || '/'
return routes[path] || notFoundComponent
})
function navigate(path) {
window.location.hash = path
}
return {
currentPath,
currentView,
navigate
}
}
```
```vue
```
## When to Use Simple Routing vs Vue Router
| Use Simple Hash Routing | Use Vue Router |
|------------------------|----------------|
| Learning/prototyping | Production apps |
| Very simple apps (2-3 pages) | Nested routes needed |
| No build step available | Navigation guards needed |
| Bundle size critical | Lazy loading needed |
| Static hosting only | History mode (clean URLs) |
## Key Points
1. **Always clean up event listeners** - Use onUnmounted or beforeUnmount
2. **Store handler reference** - Anonymous functions can't be removed
3. **Consider Vue Router for real apps** - It handles cleanup automatically
4. **Test unmount scenarios** - v-if toggling, hot module replacement
5. **Composables help encapsulate cleanup logic** - Reusable and automatic
## Reference
- [Vue.js Routing Documentation](https://vuejs.org/guide/scaling-up/routing.html)
- [Vue Router Official Library](https://router.vuejs.org/)