Files
stack/packages/mosaic/framework/skills/vue-best-practices/reference/keepalive-no-cache-removal-vue3.md
T
fargo 1a822493ba format: apply repo prettier (3.8.1) to the folded skills tree
963 markdown files reformatted with the repository's pinned prettier so
pnpm format:check covers the folded tree like every other repo file.

The formatter's embedded-language pass also normalized code fences
(TS semicolons, closed HTML tags in examples, lowercased CSS hex colors,
one renumbered list that skipped an index). Alphanumeric token deltas vs
the fold commit were audited file-by-file; all are formatter-equivalent
markup normalizations plus the four sanitized skills.
2026-08-19 14:37:17 -05:00

4.6 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Vue 3 KeepAlive Has No Direct Cache Removal API MEDIUM Unlike Vue 2, there is no way to programmatically remove a specific component from KeepAlive cache in Vue 3 gotcha
vue3
keepalive
cache
migration
vue2-to-vue3

Vue 3 KeepAlive Has No Direct Cache Removal API

Impact: MEDIUM - Vue 3 removed the $destroy() method that Vue 2 developers used to indirectly clear KeepAlive cache entries. There is no direct API to remove a specific cached component in Vue 3.

Task Checklist

  • Do not rely on programmatic cache removal from Vue 2 patterns
  • Use include/exclude props for dynamic cache control
  • Use key changes to force cache invalidation
  • Set appropriate max prop to auto-evict old entries

The Problem

Vue 2 Pattern (No Longer Works)

// Vue 2: Could destroy specific component instance
this.$children[0].$destroy();

Vue 3: No Equivalent API

// Vue 3: $destroy() does not exist
// There is NO direct way to remove a specific cached instance

Solutions

Solution 1: Dynamic Include/Exclude

Control cache membership via reactive props:

<script setup>
import { ref, computed } from 'vue';

const cachedViews = ref(['Dashboard', 'Settings', 'Profile']);

function removeFromCache(viewName) {
  cachedViews.value = cachedViews.value.filter((v) => v !== viewName);
}

function addToCache(viewName) {
  if (!cachedViews.value.includes(viewName)) {
    cachedViews.value.push(viewName);
  }
}
</script>

<template>
  <KeepAlive :include="cachedViews">
    <component :is="currentView" />
  </KeepAlive>
</template>

When a component is removed from include, it will be destroyed on next switch.

Solution 2: Key-Based Cache Invalidation

Change the key to force a fresh instance:

<script setup>
import { ref, reactive } from 'vue';

const currentView = ref('Dashboard');
const viewKeys = reactive({
  Dashboard: 0,
  Settings: 0,
  Profile: 0,
});

function invalidateCache(viewName) {
  viewKeys[viewName]++;
}

function switchView(viewName) {
  currentView.value = viewName;
}

// Force fresh Dashboard on next visit
function refreshDashboard() {
  invalidateCache('Dashboard');
}
</script>

<template>
  <KeepAlive>
    <component :is="currentView" :key="`${currentView}-${viewKeys[currentView]}`" />
  </KeepAlive>
</template>

Solution 3: Conditional KeepAlive

Wrap or unwrap based on cache need:

<script setup>
import { ref } from 'vue';

const currentView = ref('Dashboard');
const shouldCache = ref(true);

function clearCacheAndSwitch(viewName) {
  shouldCache.value = false;
  currentView.value = viewName;
  // Re-enable caching after the switch
  nextTick(() => {
    shouldCache.value = true;
  });
}
</script>

<template>
  <KeepAlive v-if="shouldCache">
    <component :is="currentView" />
  </KeepAlive>
  <component v-else :is="currentView" />
</template>

Solution 4: Use Max for Automatic Eviction

Let LRU cache handle cleanup:

<template>
  <!-- Automatically evicts least recently used when cache is full -->
  <KeepAlive :max="5">
    <component :is="currentView" />
  </KeepAlive>
</template>

Vue Router: Clear Cache on Certain Navigations

<script setup>
import { ref, watch } from 'vue';
import { useRoute } from 'vue-router';

const route = useRoute();
const cachedRoutes = ref(['Dashboard', 'Settings']);

// Clear specific route from cache when navigating from certain paths
watch(
  () => route.name,
  (newRoute, oldRoute) => {
    if (oldRoute === 'Login') {
      // User just logged in - clear and refresh Dashboard
      cachedRoutes.value = cachedRoutes.value.filter((r) => r !== 'Dashboard');
      nextTick(() => {
        cachedRoutes.value.push('Dashboard');
      });
    }
  },
);
</script>

<template>
  <router-view v-slot="{ Component }">
    <KeepAlive :include="cachedRoutes">
      <component :is="Component" />
    </KeepAlive>
  </router-view>
</template>

Key Points

  1. No $destroy() in Vue 3 - Cannot directly remove cached instances
  2. Use dynamic include - Reactively control which components are cached
  3. Use key changes - Changing key creates a new cache entry
  4. Use max prop - LRU eviction handles cleanup automatically
  5. Plan cache strategy - Design around these constraints upfront

Reference