---
title: "Vue: Solving keep-alive Memory Leaks Elegantly with `include` and Vuex"
description: "Explains how Vue's keep-alive can cause memory to grow indefinitely, and demonstrates an elegant solution that manages the include list via Vuex to precisely clear caches and avoid memory leaks."
canonical_url: "https://blog.markkulab.net/en/post/keep-alive-clear"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2022-05-06 01:01:01 +0800"
category: "Frontend"
tags: ["vue", "keep alive", "vuex", "memory leak", "frontend", "cache", "performance"]
language: "en"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "when reusing or quoting, credit the author and link back to the original"
---

# Vue: Solving keep-alive Memory Leaks Elegantly with `include` and Vuex

## The Problem
In Vue, when switching components we often don't want them to re-render — we want to remember their original state and avoid re-fetching APIs. For these reasons we use `keepAlive` to preserve state. But `keepAlive` is a double-edged sword: until you refresh the page, the longer time goes on, the more memory may keep growing, eventually leading to a memory leak.

A common UX example: in a paginated list, after navigating to page 2 and clicking into a detail page, when the user goes back, if you don't remember the previous page number or scroll position via routing, they end up back on page 1 — bad experience. This is exactly where `keepAlive` shines.

## Analyzing the Problem
After looking through plenty of references, I found Vue doesn't offer a convenient way to clear `keepAlive`. Some people use the [brute-force destroy](https://juejin.cn/post/6844903649517240328?fbclid=IwAR3w4SGnitm-uS6G3NK-Bh91KMjuQurFpBomdGtsn5nNxsDlDNEmJAYxt7M) approach, which I personally don't think is very elegant. Later I saw a [GitHub issue](https://github.com/vuejs/vue/issues/6509) where people recommended using `include` to clear the `keepAlive` cache, and I adapted that into what I needed.

## How brute-force deletion works

## Get the current component's keepAlive cache
```
this.$vnode.parent.componentInstance.cache
```
![Vue component cache showing MessageList and MessageDetail VNodes](https://blog.markkulab.net/content/markku/posts/keep-alive-clear/images/Da45peM.png)


## Get all keepAlive cache keys for the current component
```
this.$vnode.parent.componentInstance.keys
```
![Vue keep-alive cache contents displaying MessageList and MessageDetail component](https://blog.markkulab.net/content/markku/posts/keep-alive-clear/images/vcqsqWJ.png)
You could of course `forEach` the keys to brute-force clear the cache, but it's not very elegant.

## In the end, I decided to clear the keep-alive cache via `include`

### First, create a `keep-alive.js` store in Vuex
```
const state = {
  allModulekeepAlive: [] // {   moduleName: 'expert',   list: ['x'] }
}

const getters = {
  getListByModuleName: (state) => (moduleName) => {
    const module = state.allModulekeepAlive.find(x => x.moduleName === moduleName)

    if (module) {
      return module.list || []
    }

    return []
  }
}

const actions = {}

const mutations = {
  add(state, payload) {
    if (!payload.moduleName || !payload.componentName) {
      alert('快取參數不完整')
      return
    }

    const module = state.allModulekeepAlive.find(x => x.moduleName === payload.moduleName)

    if (module) {
      if (!module.list.includes(payload.componentName)) {
        module.list.push(payload.componentName)
      }
    } else {
      const newModule = {
        moduleName: payload.moduleName,
        list: [payload.componentName]
      }

      state.allModulekeepAlive.push(newModule)
    }
  },
  removeByModuleName(state, moduleName) {
    if (!moduleName) {
      alert('removeByModuleName快取參數不完整')
      return
    }

    const module = state.allModulekeepAlive.find(x => x.moduleName === moduleName)

    if (module) {
      module.list = []
    }
  },
  removeByComponentName(state, payload) {
    if (!payload.moduleName || !payload.componentName) {
      alert('removeByComponentName快取參數不完整')
      return
    }

    const module = state.allModulekeepAlive.find(x => x.moduleName === payload.moduleName)

    if (module) {
      if (module.list.includes(payload.componentName)) {
        module.list = module.list.filter(x => x !== payload.componentName)
      }
    }
  },
  cleanAll(state) {
    state.allModulekeepAlive = []
  }
}

export default {
  namespaced: true,
  state,
  actions,
  getters,
  mutations
}
```

## Now we can clear caches through these mutations

### Add a module cache entry
```
const cacheObj1 = { moduleName: 'message', componentName: 'MessageDetail' }

vm.$store.commit('keep-alive/add', cacheObj1)
```

### Remove all caches under a module
```
vm.$store.commit('keep-alive/removeByModuleName', 'message')
```

### Remove a specific ComponentName under the message module
```
const cacheObj1 = { moduleName: 'message', componentName: 'MessageDetail' }

vm.$store.commit('keep-alive/removeByComponentName', cacheObj1)
```

### Clear all caches
```
this.$store.commit('keep-alive/cleanAll')


import { mapGetters } from 'vuex'

 ...mapGetters('keep-alive', [
      'getListByModuleName',
    ])
```

## Usage example
```
<template>
  <div>
    <p>目前 message 模組下的 keep alive 的快取:{{ getListByModuleName('message') }} </p>

    <keep-alive :include="getListByModuleName('message')">
      <router-view />
    </keep-alive>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
  metaInfo: {
    title: '訊息'
  },
  // 進入頁面前
  beforeRouteEnter(to, from, next) {
    next(vm => {
      vm.$store.commit('keep-alive/removeByModuleName', 'message')

      const cacheObj1 = { moduleName: 'message', componentName: 'MessageDetail' }

      vm.$store.commit('keep-alive/add', cacheObj1)

      const cacheObj2 = { moduleName: 'message', componentName: 'MessageList' }

      vm.$store.commit('keep-alive/add', cacheObj2)
    })
  },
  // 離開頁面前
  beforeRouteLeave(to, from, next) {
    alert('清除 Message 快取')
    this.$store.commit('keep-alive/removeByModuleName', 'message')
    next()
  },
  computed: {
    ...mapGetters({
      getListByModuleName: 'keep-alive/getListByModuleName'
    })
  },

  created() {
  }
}
</script>
```

## Verifying with Vue Dev Tools
![Vue DevTools inspecting inactive MessageList component properties](https://blog.markkulab.net/content/markku/posts/keep-alive-clear/images/DCKqurD.png)

### Pattern 1 — leaving the route releases automatically, but you can release earlier via `include`
```
<keep-alive>
    <router-view>
        <!-- 所有路徑匹配到的視圖組件都會被緩存！ -->
    </router-view>
</keep-alive>
```
### Pattern 2
```
<keep-alive exclude="a">
  <component>
    <!-- 除了 name 為 a 的組件都將被緩存！ -->
  </component>
</keep-alive>可以保留它的狀態或避免重新渲染
```

## References
[Reference](https://github.com/vuejs/vue/issues/9747)
[Reference](https://gitee.com/wangxiufu/cmtter-vue-cli/blob/master/cli/appTemplates/layout/components/router/keepAlive.jsx)

---

## About this article and its author

Originally published on [Mark Ku's Tech Notes](https://blog.markkulab.net/en/post/keep-alive-clear)

License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — when reusing or quoting, credit the author and link back to the original

### About the author

**[Mark Ku](https://blog.markkulab.net/en/author/mark-ku)** — Software Solution Provider

- 10+ years senior software engineer, now an AI Builder
- Focused on large-platform architecture — North-American e-commerce, AI SaaS subscription billing
- Combining AI Agents and automation to build evolvable product foundations

### Free tools built by the author

All of these are free to use:

- [Free PDF Sign Tool](https://blog.markkulab.net/en/tools/pdf-sign): Online PDF sign tool — draw, type, or upload a signature, then drag, resize, and download. Everything runs in your browser; nothing is uploaded.
- [VS Code Refactory](https://blog.markkulab.net/en/tools/refactory): Refactory is a VS Code refactoring extension: 34 actions plus a 37-rule code-smell inspection layer with a Code Health dashboard, across 18 languages, backed by 534 tests. It learns your repo's conventions: where interfaces live, where DI is registered, whether 'use client' belongs. It ranks files by git churn × complexity so you know what to fix first, and hands any smell to the Claude Code already on your machine. Free to use, and your source never leaves your computer.
- [DB-Kit Database Manager](https://blog.markkulab.net/en/tools/db-kit): DB-Kit is a lightweight, cross-platform database manager built with Tauri + Rust + React. Manage MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, SQLite, MongoDB, Redis, Kafka, Elasticsearch and RabbitMQ from one consistent interface: passwords encrypted in the OS keychain, SSH tunnels, full CRUD, a visual query builder, stacked multi-statement result sets, cross-connection data transfer and compare/sync, Excel / CSV import & export, visualized execution plans, ER diagrams, scheduled backups, SQL stress testing with p50–p99 latency percentiles, a 15-rule SQL review engine, Kafka message browsing with monitoring & alerts, a bilingual UI (Traditional Chinese / English), a built-in AI assistant (natural-language SQL, AI review and tuning advice) and the dbk CLI. Free and open source (MIT), with installers for Windows, macOS and Linux.
- [VS Code Super Mermaid](https://blog.markkulab.net/en/tools/super-mermaid): Super Mermaid is a VS Code extension for beautiful Mermaid diagrams out of the box: auto-colored live preview, mouse pan & zoom, high-res PNG / SVG export, 21 templates and multiple themes. Free and open source (MIT).
- [React Super Mermaid](https://blog.markkulab.net/en/tools/react-super-mermaid): react-super-mermaid is an open-source React component library: render beautiful Mermaid diagrams with a single <MermaidViewer>, with built-in colorful / sketch themes, pan & zoom, in-diagram search, and high-res SVG / PNG export. Lightweight, SSR-safe, fully typed. Free and open source (MIT).
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/en/tools/jira-super-mermaid): An Atlassian Forge app: write Mermaid syntax directly inside a Jira issue or a Confluence page and get flowcharts, sequence diagrams, state machines and Gantt charts. 11 diagram types, SVG / PNG export, light and dark themes, full CJK support. Runs on Atlassian: your diagrams live in your own site and the app calls no third-party service. Free, coming soon to the Atlassian Marketplace.
- [Mermaid Live Preview](https://blog.markkulab.net/en/tools/mermaid-preview): Write Mermaid in your browser, see it render instantly, and share the whole diagram as a single link. No sign-up, nothing uploaded to a server, and mermaid.live share links work as-is.
- [React Intl Phone Number](https://blog.markkulab.net/en/tools/react-intl-phone-number): react-intl-phone-number is an open-source React component: framework-agnostic and antd-free, with E.164 in/out, a searchable flag / country-code dropdown, configurable validation levels (strict / mobile-strict / loose), themeable CSS, and i18n — phone logic powered by google-libphonenumber. Lightweight and fully typed. Free and open source (MIT).
- [Uptime Kuma Cluster](https://blog.markkulab.net/en/tools/uptime-kuma-cluster): Turn single-node Uptime Kuma into a highly available cluster: OpenResty + Lua smart load balancing, shared MariaDB state, health checks and automatic failover, plus cluster-management REST APIs. One Docker Compose command to start. Free and open source (MIT).
- [Special Education](https://blog.markkulab.net/en/education): Learning materials crafted for special education students

### Daily podcasts

- [Mark's Tech Insights — Daily AI News](https://blog.markkulab.net/en/category/tech-news): Daily curated AI and tech trends. Catch the latest developments via audio summaries — covering AI applications, software architecture, DevOps, and engineering practice. — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/en/category/ai-stock-chat): Every trading day, an AI-analyzed take on the Taiwan stock market, delivered as a two-host conversation covering the session and the next-day outlook. — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml
- [開源好物週報](https://blog.markkulab.net/en/category/open-source-weekly): A weekly two-host pick of free open-source tools surfaced from real Hacker News, GitHub, and Reddit buzz — what pain they solve and the fastest way to get started. — RSS: https://blog.markkulab.net/open-source-weekly/feed.xml

### Newsletter

[Subscribe to the newsletter](https://blog.markkulab.net/en/subscribe) — Be the first to know about new posts. No spam, unsubscribe anytime.
