About Vue lifecycle

user775630919552 2021-09-15 10:28:16

Vue Life cycle

 Life cycle flowchart .jpg

1、 Life cycle

Vue The process from creation to destruction of an instance , According to the flow chart, it can be roughly divided into four stages :

Initialization phase : by vue Initialize some properties on the instance , Events and responsive data ;

Template compilation phase : Compile the template into a rendering function ;

Mount stage : Mount the instance to the specified DOM On , Render the template to real DOM in ;

Destruction phase : Delete the instance itself from the parent component , And cancel dependency tracking and event monitoring ;

2、 Life cycle function ( hook )

In the life cycle , A function that is automatically executed at a specific point in time .

3、 Initialization phase

 Initialization phase .png

Create a vue example :new vue() == > Core code :this._init(options),_init Methods mainly implement the following methods: :

Method of execution brief introduction
initLifecycle(vm) Initialize the lifecycle , Some variables and attributes are defined . Main setup p a r e n t , parent, children,$refs,_watcher,isMounted,isDestroyed Equal flag variable
initEvents(vm) Initialize the event that the parent component binds to the instance and the binding of the event ( Don't mean DOM event ). It mainly defines o n c e once、 off、 e m i t emit、 on
initRender(vm) Initialize rendering related properties and methods , It mainly defines createElement function ( Generate virtual vnode)
callHook(vm, 'beforeCreate') perform beforeCreate Life cycle
initInjections(vm) Initialize the in the instance Inject Option
initState(vm) Data initialization , Which are initialized in order 5 An option ,props、methods、data、computed、watch. And finish data The data was hijacked observe And give from computed、watch To configure watcher Observer example , Later, when the data changes , Only in this way can we perceive the change of data and complete the rendering of the page
initProvide(vm) take provide Property is bound to provided On . and inject Pairs appear , stay initState The reason for running later is provide May use data、props、methods etc. .
callHook(vm, 'created') perform creadted Life cycle function , operation data,methods At the earliest created Life cycle function

4、 Template compilation phase

 Template compilation phase .png

At the end of the initialization phase, it will judge whether there is el Parameters , without el, We'll wait for the call $mount(el) Method . There is el In case of parameter , Judge template Judge whether there is handwriting before parameters render function , There is render Words , Will render the current render function , If not, then we start to find out if there is template Templates , without template, Then we'll take what we get directly el( That's what we're used to #app,#app There may be other labels in it ) Translate it into templae, And then I'm putting this template convert to render function .

<div id="app">{{el}}</div>
<script> var app = new Vue({ el: '#app', data: { el: ' adopt el Rendering ', template: ' adopt template Rendering ', render: ' adopt render Rendering ' }, template: '<div>{{ template }}</div>', render(h) { return h('div', this.render); } }); // The page presents adopt render Rendering  // priority render -> template -> el </script>
 Copy code 

No matter how it is used el still template Or what we often use .vue file , In the end render function .

Vue There are two versions based on the source code :1. Full version 2. Contains only the runtime version

The only difference between the two versions is that the latter includes a compiler , Have created vue example 、 Render and process virtual dom And so on , Use vue-loader or vueift when , Templates are precompiled into rendering functions at build time , The initialization phase goes directly to the mount phase , The template compilation phase only exists in the full version .

5、 Mount stage

 Mount stage .png

With render Rendering function , Trigger beforeMount Life cycle hook function , Enter the mount phase , Yes updateComponent function . Part of the source code :

callHook(vm, 'beforeMount');
let updateComponent;
updateComponent = function() {
vm._update(vm._render(), hydrating);
};
 Copy code 

You can see from the source code , Inside the function ,vm._render() The above will be called internally render function , Generate a new virtual DOM. Pass it to the component Vue.prototype._update Method to render to the page .

_update Internal methods patch, Will be based on the existence of old virtual DOM To determine whether to render for the first time or update , If there is an update on the latest virtual DOM Same old virtual as last rendered DOM Compare and update DOM node . And then start to render Rendering becomes real dom. Make it real dom after , Will render the reality dom Replace the original vm. e l . And then replace the el. And then replace the el Render to view page .

If this is the first rendering , It will vnode Conduct patch operation , Help us to vnode adopt createElm Function to create a new node and render it to dom In nodes .

We'll do it later monut Life cycle function , An attribute that identifies the lifecycle _isMounted Set as true. therefore mounted Within the function , We can operate dom Of , Because at this time dom The rendering is done .

At this time , The mount operation is half completed , Hanging not only renders the template into the view , At the same time, you should also open the data in the template ( state ) Monitoring of , When the data ( state ) Notify its dependencies for view updates when changes occur .

export function mountComponent(vm, el, hydrating) {
vm.$el = el;
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode;
}
callHook(vm, 'beforeMount');
let updateComponent;
updateComponent = () => {
vm._update(vm._render(), hydrating);
};
new Watcher(
vm,
updateComponent,
noop,
{
before() {
if (vm._isMounted) {
callHook(vm, 'beforeUpdate');
}
}
},
true /* isRenderWatcher */
);
hydrating = false;
if (vm.$vnode == null) {
vm._isMounted = true;
callHook(vm, 'mounted');
}
return vm;
}
 Copy code 

You can see from the mounted source code , Created a Watcher example , And will define the updateComponent Function is introduced to . To open the data in the template ( state ) Monitoring of .

When our state data changes , Triggered beforeUpdate Life cycle function , It's time to start rendering our changed data to the page ( Judge the current _isMounted Is it for ture also _isDestroyed Is it for false, in other words , Guarantee dom If it has been mounted , And the current component is not destroyed , To leave update technological process ).

beforeUpdate After call , We're going to regenerate another one dom(Vnode), And then I'll take this latest Vnode And the original Vnode To make a diff count , This involves a series of calculations , Calculate the minimum update range , To update render The latest data in the function , I'll update the render Function to render as real dom. That's the end of our data update

And then execute updated, therefore updated It can also be operated inside dom, And get the latest dom.

9.png

mouted and updated Implementation , It doesn't wait for all the subcomponents to be mounted before execution ,Vue It's asynchronous execution dom The updated , Once a change in data is observed ,Vue It'll turn on a Queue queue , Then loop in the same event (event loop) Changes in data were observed watcher Push into this Queue queue . If this watcher Triggered multiple times , Will only be pushed to the queue once . This kind of buffering can effectively eliminate unnecessary calculation and DOm operation . And in the next event loop ,Vue Will clear the queue , And carry out necessary DOM to update .

for example :

<template>
<div>
<ul ref="list">
<li v-for="(item, index) in list" :key="index">{{ item }}</li>
</ul>
<button @click="additem"> increase </button>
</div>
</template>
<script>
export default {
data() {
return {
list: [' first ', ' the second ', ' Third ']
};
},
methods: {
additem() {
this.list.push(' Add one more ');
this.list.push(' Add one more ');
this.list.push(' Add one more ');
let child = this.$refs.list.childNodes.length;
console.log('list The length of :', child); // The result is 3
this.$nextTick(() => {
let child = this.$refs.list.childNodes.length;
console.log('list The length of :', child); // The result is 6
});
}
}
};
</script>
 Copy code 

When the button is clicked , List loop out 6 individual , But at this time dom The number of on can only be obtained 3,dom It hasn't been updated yet . If you want to get... After modifying the data dom Updated status , have access to this.$nextTick Method .

this.$nextTick(): The next time DOM A delayed callback is executed after the update loop is completed . Use this method immediately after modifying the data , Gets the updated DOM
 Copy code 

6、 Destruction phase

 Destruction phase .png

When calling the vm.$destroy Method ,Vue The instance enters the destruction stage , The main work done in this stage is to integrate the current Vue Instance is deleted from its parent instance , Cancel all dependency tracing on the current instance and remove all event listeners on the instance .

beforeDestroy The lifecycle is before the instance is destroyed , In this function , You can still manipulate instances .

After that, we will do a series of destruction actions , Remove all kinds of data references , Remove event monitoring , Delete component _watcher, Delete sub instance , Delete yourself self etc. . At the same time, the instance properties _isDestroyed Set as true

After destruction , Re execution destroyed, At this time, the instance cannot be operated . The whole process of the life cycle is over .

summary :

Life cycle brief introduction
beforeCreated Generate o p t i o n s Options , And add life cycle related attributes to the instance . After the instance is initialized , In data observation ( d a t a o b s e r v e r ) and e v e n t / w a t c h e r The event configuration is called before , in other words , d a t a , w a t c h e r , m e t h o d s There is no such stage . But an object exists , That's it options Options , And add life cycle related attributes to the instance . After the instance is initialized , stay The data observed (data observer) and event/watcher The event configuration is called before , in other words ,data,watcher,methods There is no such stage . But an object exists , That's it route, Therefore, redirection and other operations can be performed according to the routing information at this stage .
created Initialize operations related to dependency injection , Will traverse the incoming methods The option to , Initialize option data , from o p t i o n s Get data options ( v m . options Get data options (vm. options.data), Add to data ‘ viewer ’ Object and create an observer , Definition getter、setter Memory properties . Called after the instance is created , This stage is accessible data, Use watcher、events、methods, in other words The data observed (data observer) and event/watcher Event configuration Completed . But at this time dom Not yet mounted . This phase allows execution http Request operation
beforeMount relevant render The function is called for the first time
mounted Called after the mount completes , perform render Function generation virtual dom, Create reality dom Replace virtual dom, And mount to the instance . Can operate dom, For example, event monitoring
beforeUpdate v m . d a t a After the update , fictitious d o m Called before re rendering . This hook can be modified vm.data After the update , fictitious dom Called before re rendering . This hook can be modified vm.data, It doesn't trigger additional rendering passes .
updated fictitious dom Renderer after rendering
beforeDestroy Before an instance is destroyed, it is called , In other words, the instance can still be called at this stage .
destroyed After the instance is destroyed, it is called. , All event listeners have been removed , The sub instance was destroyed .

7、 Life cycle loading sequence of parent and child components

// Child components 
Vue.component('child', {
template: '<h1>child</h1>',
props: ['message'],
beforeCreate() {
console.log('I am child beforeCreated');
},
created() {
console.log('I am child created');
},
beforeMount() {
console.log('I am child beforeMount');
},
mounted() {
console.log(this.message); // null
console.log('I am child mounted');
}
});
// Parent component 
new Vue({
el: '#app',
template: ` <div id='parent'><child :message='message'></child></div> `,
data: {
message: null
},
beforeCreate() {
console.log('I am parents beforeCreated');
},
created() {
console.log('I am parents created');
},
beforeMount() {
console.log('I am parents beforeMount');
},
mounted() {
this.message = 'this is message';
console.log('I am parents mounted');
}
});
 Copy code 

Print the log in their hook function respectively , Observe the execution sequence . The result is as follows , The parent component is created first , The subcomponent is then created ; Mount the sub assembly first , Then mount the parent component .

"I am parents beforeCreated"
"I am parents created"
"I am parents beforeMount"
"I am child beforeCreated"
"I am child created"
"I am child beforeMount"
null
"I am child mounted"
"I am parents mounted"
 Copy code 

You can see in the sub component mouted Printed out in null; After the sub assembly is mounted , The parent component has not been mounted . So when component data is echoed , In the parent component mounted The data obtained from , Subcomponents mounted You can't get it .

Load Render Pass :

Father beforeCreate-> Father created-> Father beforeMount-> Son beforeCreate-> Son created-> Son beforeMount-> Son mounted-> Father mounted

The update process :

Father beforeUpdate-> Son beforeUpdate-> Son updated-> Father updated

Destruction process :

Father beforeDestroy-> Son beforeDestroy-> Son destroyed-> Father destroyed

The life cycle loading sequence of parent and child components can also be understood according to the life cycle flow chart , The parent component must be created before the child component can be created , The child component is within the parent component , You have to update and mount first , The parent components are all mounted , If the parent component is destroyed first , It will cause inner leakage .

8、 Optimize

(1) Custom events 、 Timer and other tasks shall be destroyed in time ( Can be in beforeDestory in ), Avoid inner leakage ;

There are two ways to clean up the timer :

Method 1 : Declare and destroy in the timer's method or lifecycle function

  1. First, in the vue Example of data The name of the timer defined in :

    export default {
    data() {
    timer: null;
    }
    };
     Copy code 
  1. In the method (methods) Or page initialization (mounted()) Use timer when

    this.timer = setInterval(() => {
    // What needs to be done
    }, 1000);
     Copy code 
  1. Then destroy the life cycle function on the page (beforeDestroy()) Medium destroy timer

    export default {
    data() {
    timer: null;
    },
    beforeDestroy() {
    clearInterval(this.timer);
    this.timer = null;
    }
    };
     Copy code 

Method 2 : Use this.$once(‘hook:beforeDestory’,()=>{}); Declare and destroy directly in a method or lifecycle function that requires a timer

export default {
methods: {
fun1() {
const timer = setInterval(() => {
// What needs to be done
}, 1000);
this.$once('hook:beforeDestroy', () => {
clearInterval(timer);
timer = null;
});
}
}
};
 Copy code 

There are some problems in method one : (1)vue An instance of this timer is required in the instance , I feel a little redundant ;

(2) The timer code created and the timer code destroyed are not put together , It's usually easy to forget to clean up the timer , Not easy to maintain ;

Therefore, method 2 is recommended

(2) Parent child component requests are asynchronous

When the parent component calls the interface to pass data to the child component , The request interface response is asynchronous . Which hook in the parent component sends the request , Which hook in the subcomponent receives data . It may not be available . When sub components mounted After all the execution , At this time, the request of the parent component may return data . It can lead to , The data passed from the parent component to the child component is undefined.

Solution 1 :

<div class="test">
<children v-if="data1" :data="data1"></children>
</div>
 Copy code 

Add a condition when rendering subcomponents ,data1 Is the data returned by the parent component calling the interface . When there is data, render the sub components . This will form a natural blockage . In the parent component of created After the request in returns data , Will execute the of the subcomponent created,mounted. Finally, execute the mounted.

Solution 2 :

In the child component watch monitor , Parent component gets value , This value will change , Naturally, it can be monitored

watch:{
data:{
deep:true,
handler:function(newVal,oldVal) {
this.$nextTick(() => {
this.data = newVal
this.data = newVal.url ? newVal.url : ''
})
}
},
}
 Copy code 

Click the invoke interface from the parent component and display the child components , The sub component gets the data and listens on watch Call method and display

props:['data1'],
watch:{
data1:{
deep:true,
handler:function(newVal,oldVal) {
this.$nextTick(() => {
this.data1 = newVal
this.showData1(this.data1)
})
}
},
}
 Copy code 

(3) To avoid the updated Change state , Because this can lead to infinite cycles of updates .

fictitious dom Renderer after rendering , If modified again $vm.data, Will trigger again beforeUpdate、updated, Into the dead cycle .

(4)v-if And v-show

Both instructions can hide or show elements . When the incoming data is true It's a show ,false Will be hidden .

The difference is :v-if Will delete elements or components ( No rendering ), That is to say DOM Remove ;v-show Will use CSS In the middle of display attribute , Set it to none.v-if Is the real conditional rendering , Because it ensures that the event listeners and child components within the condition block are properly destroyed and rebuilt during the switch ; It's also inert : If the condition is false at the initial render , And do nothing —— Until the condition is true for the first time , Before the condition block is rendered .

v-if It is applicable to conditions that are rarely changed during operation , Scenes that do not need to switch conditions frequently ;v-show It is suitable for scenarios that require very frequent switching conditions .

(5)KEY Importance

Use v-for When updating the list of rendered elements , Default in place reuse policy ; When modifying the list data , He will be based on key Value to determine whether a value is modified , If modified , Then re render this item , Otherwise, reuse the previous elements ;

Should be used in the cycle key, And better not be index perhaps random.diff In the algorithm tag and key To determine whether it is the same node (sameNode), Use key You can reduce the number of renderings , Improve rendering performance .


Why not index perhaps random As key

diff In the process of algorithm , It will compare whether the old and new nodes are of the same type .

If the list of renderings is changed , use index As key, How does the order of arrays change ,index All are 0, 1, 2 It's arranged like this , When comparing old and new nodes , It can't be reused , It will re render . Empathy ,random Random number as key, The same cannot be found in comparison , It can't be reused , To render .

Please bring the original link to reprint ,thank
Similar articles