SoFunction
Updated on 2025-04-05

In-depth analysis of the use of Keep-Alive cache components in Vue

1. What is Keep-alive

Keep-alive is a built-in component in vue. It can retain state in memory during component switching, preventing repeated rendering of DOM.

Keep-alive When wrapping dynamic components, it caches inactive component instances instead of destroying them.

Keep-alive can be set as followsprops attribute

  • include - String or regular expression. Only components with matching names will be cached
  • exclude - String or regular expression. Any component with a name matching will not be cached
  • max - Number. How many component instances can be cached at most

aboutkeep-aliveBasic usage:

<keep-alive>
  <component :is="view"></component>
</keep-alive>

useincludesandexclude

&lt;keep-alive include="a,b"&gt;
  &lt;component :is="view"&gt;&lt;/component&gt;
&lt;/keep-alive&gt;
&lt;!-- Regular expressions (use `v-bind`) --&gt;
&lt;keep-alive :include="/a|b/"&gt;
  &lt;component :is="view"&gt;&lt;/component&gt;
&lt;/keep-alive&gt;
&lt;!-- Array (use `v-bind`) --&gt;
&lt;keep-alive :include="['a', 'b']"&gt;
  &lt;component :is="view"&gt;&lt;/component&gt;
&lt;/keep-alive&gt; 

First check the component's ownnameOptions, ifnameThe option is not available, then it matches its local registration name (parent componentcomponentsThe key value of the option), the anonymous component cannot be matched

The component with keep-alive cache is set, and there will be two additional life cycle hooks (activatedanddeactivated):

  • When entering a component for the first time: beforeRouteEnter > beforeCreate > created > mounted > activated > ... ... > beforeRouteLeave > deactivated
  • When entering the component again: beforeRouteEnter > activated > ... > beforeRouteLeave > deactivated

2. Use scenarios

Principle of use: When we do not need to reload the page in certain scenarios, we can usekeepalive

Take a chestnut:

When we return from home page –> list page –> trade details page –> then the list page should need to keep-alive

From home page –> list page –> trade details page –> return to list page (need to cache) –> return to home page (need to cache) –> enter the list page again (no cache required), and you can control the keep-alive of the page as needed.

Set keepAlive attribute in the route to determine whether cache is required

{
  path: 'list',
  name: 'itemList', // List page  component (resolve) {
    require(['@/pages/item/list'], resolve)
 },
 meta: {
  keepAlive: true,
  title: 'List Page'
 }
}

use<keep-alive>

&lt;div  class='wrapper'&gt;
    &lt;keep-alive&gt;
        &lt;!-- View components that require cache --&gt; 
        &lt;router-view v-if="$"&gt;&lt;/router-view&gt;
     &lt;/keep-alive&gt;
      &lt;!-- 不View components that require cache --&gt;
     &lt;router-view v-if="!$"&gt;&lt;/router-view&gt;
&lt;/div&gt;

3. Principle analysis

keep-aliveyesvueA built-in component

Source code location: src/core/components/

export default {
  name: 'keep-alive',
  abstract: true,
  props: {
    include: [String, RegExp, Array],
    exclude: [String, RegExp, Array],
    max: [String, Number]
  },
  created () {
     = (null)
     = []
  },
  destroyed () {
    for (const key in ) {
      pruneCacheEntry(, key, )
    }
  },
  mounted () {
    this.$watch('include', val =&gt; {
      pruneCache(this, name =&gt; matches(val, name))
    })
    this.$watch('exclude', val =&gt; {
      pruneCache(this, name =&gt; !matches(val, name))
    })
  },
  render() {
    /* Get the first component node in the default slot */
    const slot = this.$
    const vnode = getFirstComponentChild(slot)
    /* Get componentOptions for this component node */
    const componentOptions = vnode &amp;&amp; 
    if (componentOptions) {
      /* Get the name of the node of the component, and priority is obtained for the name field of the component. If the name does not exist, get the tag of the component */
      const name = getComponentName(componentOptions)
      const { include, exclude } = this
      /* If the name is not in inlcude or exists in exlude, it means that it is not cached and directly returns vnode */
      if (
        (include &amp;&amp; (!name || !matches(include, name))) ||
        // excluded
        (exclude &amp;&amp; name &amp;&amp; matches(exclude, name))
      ) {
        return vnode
      }
      const { cache, keys } = this
      /* Get the key value of the component */
      const key =  == null
        // same constructor may get registered as different local components
        // so cid alone is not enough (#3269)
        ?  + ( ? `::${}` : '')
        : 
     /* After getting the key value, go to the object to find out whether the value is present. If so, it means that the component has a cache, that is, hit cache */
      if (cache[key]) {
         = cache[key].componentInstance
        // make current key freshest
        remove(keys, key)
        (key)
      }
        /* If there is no hit cache, set it into cache */
        else {
        cache[key] = vnode
        (key)
        // prune oldest entry
        /* If max is configured and the cache length exceeds, delete the first one from the cache */
        if ( &amp;&amp;  &gt; parseInt()) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode)
        }
      }
       = true
    }
    return vnode || (slot &amp;&amp; slot[0])
  }
}

You can see that the component does not havetemplate, but usedrender, will be automatically executed when the component is renderedrenderfunction

Is an object used to store components that need to be cached, and it will be stored in the following form:

 = {
    'key1':'Component 1',
    'key2':'Component 2',
    // ...
}

Execute when component is destroyedpruneCacheEntryfunction

function pruneCacheEntry (
  cache: VNodeCache,
  key: string,
  keys: Array&lt;string&gt;,
  current?: VNode
) {
  const cached = cache[key]
  /* Determine that there is no component currently in the rendered state and destroy it*/
  if (cached &amp;&amp; (!current ||  !== )) {
    .$destroy()
  }
  cache[key] = null
  remove(keys, key)
}

existmountedObservation in hook functionincludeandexcludeThe changes are as follows:

mounted () {
    this.$watch('include', val => {
        pruneCache(this, name => matches(val, name))
    })
    this.$watch('exclude', val => {
        pruneCache(this, name => !matches(val, name))
    })
}

ifincludeorexcludeThere has been a change, that is, the rules that define the components that need to be cached or the rules that do not need to be cached have changed, then it will be executed.pruneCacheFunctions, the functions are as follows:

function pruneCache (keepAliveInstance, filter) {
  const { cache, keys, _vnode } = keepAliveInstance
  for (const key in cache) {
    const cachedNode = cache[key]
    if (cachedNode) {
      const name = getComponentName()
      if (name && !filter(name)) {
        pruneCacheEntry(cache, key, keys, _vnode)
      }
    }
  }
}

The object is traversed within this function, the name value of each item is taken out, and the new cache rule is used to match it. If the match is not up, it means that the component does not need to be cached under the new cache rule. Then call the pruneCacheEntry function to remove it from the object

The most powerful cache function about keep-alive is implemented in the render function

First get the key value of the component:

const key =  == null? 
 + ( ? `::${}` : '')
: 

Get itkeyGo after it's worth itLook for whether the value is present in the object. If so, it means that the component has a cache, that is, hit cache, as follows:

/* If the cache is hit, take the vnode component instance directly from the cache */
if (cache[key]) {
     = cache[key].componentInstance
    /* Adjust the order of the component key, delete it from the original place and re-place it in the last */
    remove(keys, key)
    (key)
} 

Get it directly from the cachevnodeComponent instance, then readjust the componentkeyIn order, delete it from the original place and replace itThe last one

There is no such objectkeyThe value situation is as follows:

/* If there is no hit cache, set it into cache */
else {
    cache[key] = vnode
    (key)
    /* If max is configured and the cache length exceeds, delete the first one from the cache */
    if ( &amp;&amp;  &gt; parseInt()) {
        pruneCacheEntry(cache, keys[0], keys, this._vnode)
    }
}

Indicates that the component has not been cached yet, then the component'skeyas keys, componentsvnodeis a value, save it inandkeySavemiddle

Then make a judgmentWhether the number of cache components in the file exceeds the maximum cache number set, if it exceeds, delete the first cache component

4. How to get data after cache

There are two solutions:

  • beforeRouteEnter

  • actived

actived

beforeRouteEnter

Every time the component is rendered, it will be executedbeforeRouteEnter

beforeRouteEnter(to, from, next){
    next(vm=&gt;{
        (vm)
        // Every time you enter the route execution        ()  // Get data    })
},

actived

existkeep-aliveWhen the cached component is activated, it will be executedactivedhook

activated(){
   () // Get data},

Note: During server-side renderingavtivedNot called

This is the article about the syntax and principle analysis of the Keep-Alive cache component usage in Vue. For more related contents of the keep-Alive cache component, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!