This is the fourth day of my participation in Gwen Challenge

Note: the following is personal understanding, if there is wrong also hope to correct!

When wrapping a dynamic component, it caches inactive component instances rather than destroying them. It does not render a DOM element by itself, nor does it appear in the parent component chain of a component. When a component is switched inside, activated and deactivated trigger the lifecycle hook functions that are active and inactive

Keep alive – use

  • The requirement completes the cache configuration for a component
<div id="app">
    <keep-alive include="test">
        <test></test>
        <demo></demo>
    </keep-alive>
</div>

const test = {
    name:'test'.template:"<div> {{ componentsName }} </div>".data(){
        return {
            componentName:'test Test component '}},activated(){
        console.log('test-activated')}}const demo = {
    name:'demo'.template:"<div> {{ name }} </div>".data(){
        return {
            componentName:'Demo Test Component'}},activated(){
        console.log('demo_keep-alive')}}const vm = new Vue({
    components:{
        test,
        demo
    },
    el:'#app'
})
Copy the code

We found that the page only displays the first test component, wondering why I only have Test, where is the demo component? With these questions we open the vue source to see why….

Source code analysis

I’ll stick main source into come in, including code comments, component files address: / SRC/core/components/keep – alive. Js

  • Check whether the configuration matches the current component name
function matches (pattern: string | RegExp | Array<string>, name: string) :boolean {
  if (Array.isArray(pattern)) {
    return pattern.indexOf(name) > -1
  } else if (typeof pattern === 'string') {
    return pattern.split(', ').indexOf(name) > -1
  } else if (isRegExp(pattern)) {
    return pattern.test(name)
  }
  /* istanbul ignore next */
  return false
}
Copy the code
  • Match the condition and clear the cache
function pruneCache (keepAliveInstance: any, filter: Function) {
  const { cache, keys, _vnode } = keepAliveInstance
  for (const key in cache) {
    constcachedNode: ? VNode = cache[key]if (cachedNode) {
      constname: ? string = getComponentName(cachedNode.componentOptions)if(name && ! filter(name)) { pruneCacheEntry(cache, key, keys, _vnode) } } } }Copy the code
  • Create cache objects and save component keys
created () {
    this.cache = Object.create(null)
    this.keys = []
 }
Copy the code
  • Watch listens for configuration changes
mounted () {
    // Listen on configuration and reset cache information
    this.$watch('include'.val= > {
      pruneCache(this.name= > matches(val, name))
    })
    this.$watch('exclude'.val= > {
      pruneCache(this.name= >! matches(val, name)) }) }Copy the code
  • Execute render method
// Execute render
  render () {
    const slot = this.$slots.default
    // Get the first child of the kepp-alive component vndoe
    const vnode: VNode = getFirstComponentChild(slot)
    constcomponentOptions: ? VNodeComponentOptions = vnode && vnode.componentOptionsif (componentOptions) {
      // Get the component name
      constname: ? string = getComponentName(componentOptions)const { include, exclude } = this;
      // Check if there is a need to cache, do not need to go directly to this if
      if (
        // Includes and does not get the name value or whether include contains the name value(include && (! name || ! matches(include, name))) ||// Whether to whitelist and filter directly
        (exclude && name && matches(exclude, name))
      ) {
        return vnode
      }
      // Cache logic is required
      const { cache, keys } = this
      // Check whether there is a key. If there is no key, vUE automatically adds a key to it
      constkey: ? string = vnode.key ==null
        ? componentOptions.Ctor.cid + (componentOptions.tag ? ` : :${componentOptions.tag}` : ' ')
        : vnode.key
      // Whether there is component data cached or directly cached
      if (cache[key]) {
          // Assign the cached vNode
        vnode.componentInstance = cache[key].componentInstance
        // Reposition the component key so that if the data has been accessed recently, it is more likely to be accessed in the future
        remove(keys, key)
        keys.push(key)
      } else {
        // Save cached vNode data
        cache[key] = vnode
        / / add the key
        keys.push(key)
        // Determine whether the maximum cache value is exceeded
        if (this.max && keys.length > parseInt(this.max)) {
          // Delete the first saved vnode
          pruneCacheEntry(cache, keys[0], keys, this._vnode)
        }
      }
      // Add the keepAlive = true flag
      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])}Copy the code

conclusion

As a general caching process, Vue has a built-in component that maintains the key names of cached objects and cached components, enhances the include you pass in, Exclude determines whether the current component needs to be cached, and we found in the Render function that the component will always take the first child component, while the demo component in our case will never be displayed. There is a way to wrap it around another built-in component that Vue provides, and display that Component, then keep-alive raises whether the current component is whitelisted or not included. Then return vnode directly. If the cached vnode is encountered, check whether the cached object already exists (there is a small detail, readjust the position of the key components, the purpose is to if the data was recently visited, so in the future to be accessed at higher risk of, because can cache to certain Max quantity, will have to delete the stack vnode, this time is according to the key position in operation), there is no word to add records to the cache object