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/keepalive-router-nested-double-mount.md
1---2title: KeepAlive with Nested Routes Double Mount Issue3impact: HIGH4impactDescription: Using KeepAlive with nested Vue Router routes can cause child components to mount twice5type: gotcha6tags: [vue3, keepalive, vue-router, nested-routes, double-mount, bug]7---89# KeepAlive with Nested Routes Double Mount Issue1011**Impact: HIGH** - When using `<KeepAlive>` with nested Vue Router routes, child route components may mount twice. This is a known issue that can cause duplicate API calls, broken state, and confusing behavior.1213## Task Checklist1415- [ ] Test nested routes thoroughly when using KeepAlive16- [ ] Avoid mixing KeepAlive with deeply nested route structures17- [ ] Use workarounds if double mount is observed18- [ ] Consider alternative caching strategies for nested routes1920## The Problem2122```vue23<!-- App.vue -->24<template>25<router-view v-slot="{ Component }">26<KeepAlive>27<component :is="Component" />28</KeepAlive>29</router-view>30</template>31```3233```javascript34// router.js35const routes = [36{37path: '/parent',38component: Parent,39children: [40{41path: 'child',42component: Child // This may mount TWICE!43}44]45}46]47```4849**Symptoms:**50- `onMounted` called twice in child component51- Duplicate API requests52- State initialization runs twice53- Console logs appear doubled5455## Diagnosis5657Add logging to confirm the issue:5859```vue60<!-- Child.vue -->61<script setup>62import { onMounted, onActivated } from 'vue'6364let mountCount = 06566onMounted(() => {67mountCount++68console.log('Child mounted - count:', mountCount)69// If you see "count: 2", you have the double mount issue70})7172onActivated(() => {73console.log('Child activated')74})75</script>76```7778## Workarounds7980### Option 1: Use `useActivatedRoute` Pattern8182Don't use `useRoute()` directly with KeepAlive:8384```vue85<script setup>86import { ref, onActivated } from 'vue'87import { useRoute } from 'vue-router'8889// Problem: useRoute() can cause issues with KeepAlive90// const route = useRoute()9192// Solution: Get route info in onActivated93const routeParams = ref({})9495onActivated(() => {96const route = useRoute()97routeParams.value = { ...route.params }98})99</script>100```101102### Option 2: Avoid KeepAlive for Nested Route Parents103104Only cache leaf routes, not parent layouts:105106```vue107<script setup>108import { computed } from 'vue'109import { useRoute } from 'vue-router'110111const route = useRoute()112113// Only cache specific leaf routes114const cachedRoutes = computed(() => {115// Don't cache parent routes that have children116return ['UserProfile', 'UserSettings'] // Only leaf components117})118</script>119120<template>121<router-view v-slot="{ Component, route: currentRoute }">122<KeepAlive :include="cachedRoutes">123<component :is="Component" :key="currentRoute.fullPath" />124</KeepAlive>125</router-view>126</template>127```128129### Option 3: Guard Against Double Initialization130131Protect your component from double mount effects:132133```vue134<script setup>135import { ref, onMounted } from 'vue'136137const isInitialized = ref(false)138139onMounted(() => {140if (isInitialized.value) {141console.warn('Double mount detected, skipping initialization')142return143}144isInitialized.value = true145146// Safe to initialize147fetchData()148setupEventListeners()149})150</script>151```152153### Option 4: Use Route-Level Cache Control154155```vue156<!-- App.vue -->157<script setup>158import { computed } from 'vue'159import { useRoute } from 'vue-router'160161const route = useRoute()162163// Define which routes should be cached in route meta164const shouldCache = computed(() => {165return route.meta.keepAlive !== false166})167</script>168169<template>170<router-view v-slot="{ Component }">171<KeepAlive v-if="shouldCache">172<component :is="Component" />173</KeepAlive>174<component v-else :is="Component" />175</router-view>176</template>177```178179```javascript180// router.js181const routes = [182{183path: '/parent',184component: Parent,185meta: { keepAlive: false }, // Don't cache parent routes186children: [187{188path: 'child',189component: Child,190meta: { keepAlive: true } // Cache leaf routes191}192]193}194]195```196197### Option 5: Flatten Route Structure198199Avoid nesting if possible:200201```javascript202// Instead of nested routes203const routes = [204// Flat structure avoids the issue205{ path: '/users', component: UserList },206{ path: '/users/:id', component: UserDetail },207{ path: '/users/:id/settings', component: UserSettings }208]209```210211## Key Points2122131. **Known Vue Router issue** - Double mount with KeepAlive + nested routes2142. **Watch for symptoms** - Duplicate API calls, doubled logs2153. **Avoid caching parent routes** - Only cache leaf components2164. **Add initialization guards** - Protect against double execution2175. **Test thoroughly** - This issue may not appear immediately218219## Reference220- [Vue Router Issue #626: keep-alive in nested route mounted twice](https://github.com/vuejs/router/issues/626)221- [GitHub: vue3-keep-alive-component workaround](https://github.com/emiyalee1005/vue3-keep-alive-component)222- [Vue.js KeepAlive Documentation](https://vuejs.org/guide/built-ins/keep-alive.html)223