This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money

What is the Vue life cycle? Why are you still asking me this stupid street question?

  • Test your proficiency
  • Measure your depth
  • Examine your knowledge

Some of you can name the following hook functions, and some of you can’t even name these hook functions, which really needs to be added, because these hook functions are only the tip of the iceberg of the full Vue life cycle

Source code address: SRC /shared/ constants.js-9 line

export const LIFECYCLE_HOOKS = [
  'beforeCreate'.'created'.'beforeMount'.'mounted'.'beforeUpdate'.'updated'.'beforeDestroy'.'destroyed'.'activated'.'deactivated'.'errorCaptured'.'serverPrefetch'
]
Copy the code

The full life cycle of Vue can be roughly divided into four phases

  • Initialization phase: Initializes some events, attributes, and reactive data for the Vue instance
  • Template compilation phase: put what we wrote<template></template>Templates are compiled into rendering functionsrender
  • Mount phase: Render templates to real DOM nodes and perform updates when data changes
  • Destruction phase: Removes the component instance from the parent component and cancels dependency and event listening

How are these four stages divided? Here is a picture (from Vue Chinese community).

The hook function is called at the end of each lifecycle. The hook function is called at the end of each lifecycle

Initialization phase

new Vue()

The first thing we do in this phase is create a Vue instance object with new

new Vue({
    el:'#app',
    store,
    router,
    render: h= > h(App)
})
Copy the code

If you can use new there must be a constructor, so let’s see

Source address: SRC/core/instance/index, js – 8

function Vue (options) {
  if(process.env.NODE_ENV ! = ='production' && !(this instanceof Vue) ) {
    warn('Vue is a constructor and should be called with the `new` keyword')}this._init(options)
}
initMixin(Vue)
Copy the code

So the key to new Vue() is _init(), so let’s see where it comes from and what it does

_init()

Source address: SRC/core/instance/init. Js – 15 lines

I’ve left out a little bit of environmental judgment, and the main process is this

  • Merge configuration, mainly to put some built-in components<component/>,<keep-alive>,<transition>,directive,filterThe list of hook function names from the beginning of this article is merged into vue. options
  • I’m calling some initialization functions, and what exactly is being initialized here I wrote down in the comments
  • Triggers the lifecycle hook,beforeCreatecreated
  • The last call$mountMount to the next stage
export function initMixin (Vue: Class<Component>) {
  // Add the _init method to the prototype
  Vue.prototype._init = function (options? :Object) {
    // Save the current instance
    const vm: Component = this
    // Merge the configuration
    if (options && options._isComponent) {
      // Mount the functions and listeners of the parent component to options and specify $options for the component
      initInternalComponent(vm, options)
    } else {
      // Merge the options we passed in with the current constructor and the parent options and mount it to the prototype
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    vm._self = vm
    initLifecycle(vm) $parent, $children, $refs, $root, _watcher... Etc.
    initEvents(vm) // Initialize events: $on, $off, $emit, $once
    initRender(vm) // Initialize render: render, mixin
    callHook(vm, 'beforeCreate') // Call the lifecycle hook function
    initInjections(vm) // Initialize inject
    initState(vm) // Initialize component data: props, data, methods, watch, computed
    initProvide(vm) // initialize provide
    callHook(vm, 'created') // Call the lifecycle hook function

    if (vm.$options.el) {
      // If el is passed, $mount will be called to enter the template compilation and mount phase
      // If not, you need to manually execute $mount to proceed to the next stage
      vm.$mount(vm.$options.el)
    }
  }
}
Copy the code

Remember what configuration was merged, what was initialized, when the two lifecycle hook functions were called, and then $mount was called to proceed to the next phase

Template compilation stage

So let’s look at the picture and see what we’re doing at this stage

$mount()

Dist/vue.js-11927

  Vue.prototype.$mount = function ( el, hydrating ) {
    el = el && query(el);
    var options = this.$options;
    // If there is no render
    if(! options.render) {var template = options.template;
      // check if there is a template
      if (template) {
        if (typeof template === 'string') {
          if (template.charAt(0) = = =The '#') { template = idToTemplate(template); }}else if (template.nodeType) {
          template = template.innerHTML;
        } else {
          return this
        }
      // If there is el
      } else if(el) { template = getOuterHTML(el); }}return mount.call(this, el, hydrating)
  };
Copy the code

$mount = $mount = $mount = $mount = $mount = $mount = $mount = $mount = $mount = $mount

<div id='app'>
    <p>{{ name }}</p>
</div>
<script>
    new Vue({
        el:'#app'.data: {name:'MuHua' },
        template:'< div > Denver < / div >'.render(h){
            return h('div', {}, 'Good good study, day day up')}})</script>
Copy the code

This might be a little awkward, but imagine what happens when you execute code like the one above

Because the source code is the first to determine whether render exists, if so, directly use the render function

If not, then template and EL, if template is present, then el is ignored

So the priority order is render > template > el

Either template or el will be compiled into the render function, and if you already have the render function, skip the previous compilation

What about template compilation? How to render? More detailed content is a little more, specific can see my other article has the complete source code process details render function is how to come? Simple template compilation in Vue

Once you get the Render function, you’re ready for the mount phase

Mount the stage

So let’s look at the picture and see what we’re doing at this stage

As you can see from the diagram, there are two main things to do here

  1. Create a real DOM node based on the virtual DOM returned by Render, insert it into the view, and finish rendering
  2. Reactive processing of data or state in a template

mountComponent()

Let’s look at the source code for the mount. Here I have deleted a little bit about the environment judgment to see the main flow

The main thing we’re doing here is

  • Calling hook functionsbeforeMount
  • call_update()Method to the old and new virtual DOMpatchAs well asnew WatcherReactive processing of template data
  • Call the hook functionmounted

Source address: SRC/core/instance/lifecycle. The js – 141 line

export function mountComponent (vm: Component, el: ? Element, hydrating? : boolean) :Component {
  vm.$el = el
  // Check whether there is a render function
  if(! vm.$options.render) {// If not, a comment node is created by default
    vm.$options.render = createEmptyVNode
  }
  // Call the lifecycle hook function
  callHook(vm, 'beforeMount')
  let updateComponent
  updateComponent = () = > {
    // Call _update to patch (Diff) the virtual DOM returned by render to the real DOM for the first time
    vm._update(vm._render(), hydrating)
  }
  // Set an observer for the current component instance to monitor the data obtained by the updateComponent function, as described below
  new Watcher(vm, updateComponent, noop, {
    // When an update is triggered, it is called before the update
    before () {
      // Check whether the DOM is mounted, that is, it will not be executed during the first rendering and unloading
      if(vm._isMounted && ! vm._isDestroyed) {// Call the lifecycle hook function
        callHook(vm, 'beforeUpdate')}}},true /* isRenderWatcher */)
  hydrating = false
  // There is no old vNode, indicating the first rendering
  if (vm.$vnode == null) {
    vm._isMounted = true
    // Call the lifecycle hook function
    callHook(vm, 'mounted')}return vm
}
Copy the code

Watcher

About the response type principle, you can see my other article introduced in detail will not move over, simple Vue response type principle source code analysis

_update()

Then understand the entrance to patch, the complete process analysis of the source code of Diff algorithm, you can see my other article is very detailed, I will not move over, simple and simple virtual DOM and Diff algorithm, and Vue2 and Vue3 in the difference

Source address: SRC/core/instance/lifecycle. Js – 59

Vue.prototype._update = function (vnode: VNode, hydrating? : boolean) {
    const vm: Component = this
    const prevEl = vm.$el // Root node of the current component
    const prevVnode = vm._vnode / / old vnode
    vm._vnode = vnode // Update the old vNode
    // Render for the first time
    if(! prevVnode) {// Patch vnode to create a real DOM and mount it to vm.$el
      vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)}else {
      // During the modification, compare the old and new vNodes and return the modified real DOM
      vm.$el = vm.__patch__(prevVnode, vnode)
    }
    // Delete the reference to the old root node
    if (prevEl) prevEl.__vue__ = null
    // Update the reference to the current root node
    if (vm.$el) vm.$el.__vue__ = vm
    // Update the parent reference
    if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
      vm.$parent.$el = vm.$el
    }
  }
Copy the code

Destruction of phase

So let’s look at the picture and see what we’re doing at this stage

Vue is now in the destruction phase when the vm.$destroy() method is called.

$destroy()

This stage is relatively simple, source code is not much, mainly is:

  • Call the lifecycle hook functionbeforeDestory
  • Removes the current component from the parent component
  • Remove all observers within the current component (dependency tracing), remove references to data objects, and remove the virtual DOM
  • Call the lifecycle hook functiondestoryed
  • Disable all event listening, remove references to the current root component, and remove references to the parent

I’ve put every line in the comments, so look at that

Source address: SRC/core/instance/lifecycle. The js – 97 line

Vue.prototype.$destroy = function () {
    const vm: Component = this
    // If the instance is in the process of being destroyed, skip it
    if (vm._isBeingDestroyed) {
      return
    }
    // Call the lifecycle hook function
    callHook(vm, 'beforeDestroy')
    // Update the destruction process status
    vm._isBeingDestroyed = true
    // Get the parent
    const parent = vm.$parent
    // If the parent exists and is not being destroyed, and is not an abstract component but a real one (
      
        is an abstract component, its abstract is true)
      
    if(parent && ! parent._isBeingDestroyed && ! vm.$options.abstract) {// Remove the current component from the parent
      remove(parent.$children, vm)
    }
    // Remove all observers of the instance
    if (vm._watcher) {
      // Remove instance dependencies
      vm._watcher.teardown()
    }
    let i = vm._watchers.length
    while (i--) {
      // Remove the dependency of data within the instance on other data
      vm._watchers[i].teardown()
    }
    // Delete the reference to the data object
    if (vm._data.__ob__) {
      vm._data.__ob__.vmCount--
    }
    // Update the component destruction status
    vm._isDestroyed = true
    // Delete the virtual DOM of the instance
    vm.__patch__(vm._vnode, null)
    // Call the lifecycle hook function
    callHook(vm, 'destroyed')
    // Turn off all event listening
    vm.$off()
    // Remove the reference to the current root component
    if (vm.$el) {
      vm.$el.__vue__ = null
    }
    // Delete the parent reference
    if (vm.$vnode) {
      vm.$vnode.parent = null}}Copy the code

When $destroy() is called

SRC /core/vdom/patch.js; SRC /core/vdom/patch.js

  • The new vnode does not exist. If the old vnode exists, the destroy function of the corresponding vnode is triggered. Line 702
  • If the new vNode root node is modified, call destroy of the component corresponding to the old vnode. Line 767
  • After the comparison between the old and new VNodes is complete, invoke destroy of the component corresponding to the old vNode. Line 795

At this point, the full Vue life cycle is complete

Past wonderful

  • Simple Vue response type source code analysis
  • Where does the render function come from? Simple template compilation in Vue
  • Simple virtual DOM and Diff algorithms, and Vue2 and Vue3 differences
  • Vue3 7 and Vue2 12 components communication, worth collecting
  • What are the latest updates to Vue3.2
  • JavaScript advanced knowledge
  • Front-end anomaly monitoring and DISASTER recovery
  • 20 minutes to help you learn HTTP and HTTPS, and consolidate your HTTP knowledge

conclusion

If this article is of any help to you, please give it a thumbs up. Thank you