Vue 3 KeepAlive: Routen-Cache, Zustandserhalt und Speicherkontrolle
<KeepAlive> ist Vue's eingebaute Komponente zum Cachen inaktiver Component-Instanzen. Sie ist nützlich, wenn ein Nutzer eine Seite verlässt und später zurückkehrt, ohne Filter, Formularzustand, Scrollposition oder lokale UI-Zustände zu verlieren.
KeepAlive lässt sich aber leicht falsch einsetzen. Wenn jede Route gecacht wird, wächst der Speicher. Wenn alte Daten nie aktualisiert werden, sehen Nutzer veraltete Informationen. Wenn Component-Namen und Route-Keys nicht kontrolliert sind, verhält sich der Cache anders als erwartet.
Referenzen:
Wann KeepAlive sinnvoll ist
Nutze KeepAlive für Seiten, bei denen lokaler Zustand den Workflow verbessert:
- Listen mit Filtern, Suche, Tabs und Scrollposition.
- Mehrstufige Formulare, bei denen Nutzer kurz eine andere Seite prüfen.
- Dashboards mit teurem lokalen Rendering.
- Admin-Tabs, die beim Wechsel nicht zurückgesetzt werden sollen.
Vermeide KeepAlive, wenn:
- Die Seite günstig neu erstellt werden kann.
- Die Seite immer frische Daten zeigen muss.
- Die Seite sensible Daten enthält, die beim Verlassen verschwinden sollen.
- Die Komponente Timer, Subscriptions oder große Objekte hält, die schwer zu pausieren sind.
Die Standardeinstellung sollte selektives Caching sein, nicht das Cachen jeder Route.
Basis-Setup für Routen
Vue Router stellt die gerenderte Route über den RouterView-Slot bereit. Dort lässt sich KeepAlive sauber einbauen.
<!-- App.vue -->
<template>
<RouterView v-slot="{ Component, route }">
<KeepAlive :include="cachedComponentNames" :max="8">
<component
v-if="route.meta.keepAlive"
:is="Component"
:key="route.meta.cacheKey || route.name"
/>
</KeepAlive>
<component
v-if="!route.meta.keepAlive"
:is="Component"
:key="route.fullPath"
/>
</RouterView>
</template>
<script setup lang="ts">
const cachedComponentNames = ["UserList", "OrderList", "ReportDashboard"]
</script>
Route-Metadaten halten die Entscheidung nahe an der Routendefinition.
// router.ts
import type { RouteRecordRaw } from "vue-router"
export const routes: RouteRecordRaw[] = [
{
path: "/users",
name: "Users",
component: () => import("./views/UserList.vue"),
meta: {
keepAlive: true,
cacheKey: "users-list"
}
},
{
path: "/users/:id",
name: "UserDetail",
component: () => import("./views/UserDetail.vue"),
meta: {
keepAlive: false
}
}
]
Halte Component-Namen stabil, wenn du include oder exclude nutzt, da Vue nach Namen matcht.
<!-- UserList.vue -->
<script setup lang="ts">
defineOptions({
name: "UserList"
})
</script>
Daten aktualisieren, ohne UI-Zustand zu verlieren
Der häufigste Fehler sind veraltete Daten. Eine gecachte Seite kann alte API-Ergebnisse behalten, nachdem der Nutzer zurückkehrt.
Nutze onActivated, um zu prüfen, ob Daten aktualisiert werden sollen. Lade nicht blind bei jeder Aktivierung neu, sonst verlierst du einen Teil des Cache-Nutzens.
<script setup lang="ts">
import { onActivated, onDeactivated, ref } from "vue"
const users = ref<User[]>([])
const loading = ref(false)
const lastLoadedAt = ref(0)
const STALE_AFTER_MS = 60_000
async function loadUsers() {
loading.value = true
try {
users.value = await fetchUsers()
lastLoadedAt.value = Date.now()
} finally {
loading.value = false
}
}
onActivated(() => {
const isStale = Date.now() - lastLoadedAt.value > STALE_AFTER_MS
if (!users.value.length || isStale) {
void loadUsers()
}
})
onDeactivated(() => {
// Pause work that should not continue while the page is hidden.
})
</script>
So bleibt lokaler UI-Zustand erhalten, während alte Daten bei Bedarf aktualisiert werden.
Scrollposition erhalten
KeepAlive erhält die Component-Instanz, aber Scrollverhalten kann trotzdem durch Layout, Transitions oder Scrollcontainer beeinflusst werden.
Für einen scrollbaren Container kannst du die Position speichern und wiederherstellen:
<template>
<main ref="scrollEl" class="page-scroll">
<!-- list content -->
</main>
</template>
<script setup lang="ts">
import { nextTick, onActivated, onDeactivated, ref } from "vue"
const scrollEl = ref<HTMLElement | null>(null)
let savedTop = 0
onDeactivated(() => {
savedTop = scrollEl.value?.scrollTop ?? 0
})
onActivated(async () => {
await nextTick()
if (scrollEl.value) {
scrollEl.value.scrollTop = savedTop
}
})
</script>
Teste direkte Navigation, Zurück-Button und programmgesteuerte Routenwechsel.
Cache-Größe begrenzen
max begrenzt, wie viele Component-Instanzen KeepAlive speichert. Wenn die Grenze überschritten wird, entfernt Vue ältere Cache-Einträge.
<KeepAlive :max="8">
<component :is="Component" />
</KeepAlive>
Wähle den Wert nach echten Nutzer-Workflows. Kleine Admin-Apps brauchen oft nur wenige gecachte Listen. Setze den Wert nicht sehr hoch, nur um State-Management-Probleme zu verstecken.
Speicherlecks vermeiden
Gecachte Komponenten werden deaktiviert, nicht unmounted. Manche Aufräumarbeiten gehören daher in onDeactivated, finale Aufräumarbeiten weiterhin in onUnmounted.
Pausiere oder entferne:
- Intervalle und Timeouts.
- WebSocket- oder SSE-Listener, die im Hintergrund nicht laufen sollen.
- ResizeObserver und IntersectionObserver.
- Globale Event Listener.
- Große temporäre Arrays, Maps oder Blobs.
import { onActivated, onDeactivated, onUnmounted } from "vue"
let timer: number | undefined
function startPolling() {
timer = window.setInterval(refreshStatus, 15_000)
}
function stopPolling() {
if (timer) {
window.clearInterval(timer)
timer = undefined
}
}
onActivated(startPolling)
onDeactivated(stopPolling)
onUnmounted(stopPolling)
Wenn Speicher nach wiederholter Navigation weiter wächst, nutze Browser-Devtools statt zu raten.
Cache-Keys und dynamische Routen
Dynamische Routen brauchen bewusste Keys. Wenn Detailseiten denselben Component-Namen und denselben Key nutzen, teilen sie eventuell eine Cache-Instanz.
<!-- Share one cached instance for the user list -->
<component :is="Component" :key="route.name" />
<!-- Separate cache entry for each route parameter -->
<component :is="Component" :key="route.fullPath" />
<!-- Controlled custom key -->
<component :is="Component" :key="route.meta.cacheKey || route.fullPath" />
Nutze fullPath nicht leichtfertig für Listen mit vielen Query-Kombinationen. Das kann zu viele Cache-Einträge erzeugen.
Praktische Regeln
Nutze KeepAlive für wertvollen lokalen Zustand, nicht als allgemeinen Performance-Schalter.
Gute Kandidaten:
- Suchergebnislisten.
- Formularentwürfe.
- Dashboards mit teurem Chart-Setup.
- Tabs, die sofort zurückkehren sollen.
Schlechte Kandidaten:
- Login- und Auth-Seiten.
- Zahlungs- oder sicherheitssensible Seiten.
- Seiten, die jedes Mal neu laden müssen.
- Detailseiten mit vielen IDs ohne klare Grenze.
Abschluss-Checkliste
Vor dem Release prüfen:
- Nur ausgewählte Routen nutzen KeepAlive.
- Gecachte Components haben stabile Namen.
- Dynamische Routen haben bewusste Keys.
maxist sinnvoll gesetzt.- Daten werden bei Bedarf über
onActivatedaktualisiert. - Timer, Observer und Listener pausieren bei Deaktivierung.
- Sensible Seiten werden nicht gecacht.
- Zurück-Button, direkte Navigation und Tabwechsel sind getestet.
KeepAlive ist zuverlässig, wenn es als Zustandserhalt behandelt wird, nicht als automatische Performance-Magie.
Probiere diese browser-lokalen Tools aus — keine Registrierung erforderlich →