[Angular 基礎(chǔ)] - 生命周期函數(shù)
之前的筆記:
-
[Angular 基礎(chǔ)] - Angular 渲染過程 & 組件的創(chuàng)建
-
[Angular 基礎(chǔ)] - 數(shù)據(jù)綁定(databinding)
-
[Angular 基礎(chǔ)] - 指令(directives)
以上為靜態(tài)頁面,即不涉及到跨組件交流的內(nèi)容
以下涉及到組件內(nèi)的溝通,從這開始數(shù)據(jù)就“活”了
-
[Angular 基礎(chǔ)] - 自定義事件 & 自定義屬性
-
[Angular 基礎(chǔ)] - 視圖封裝 & 局部引用 & 父子組件中內(nèi)容傳遞
看了一下,從 v2 開始的生命周期好像就沒變過,這是從 archive 的 v2 官網(wǎng)上拉下來的一張圖:
數(shù)量和順序都是一樣的,藍(lán)色部分則是與 投射(projection) 有關(guān)
這篇筆記相對(duì)而言比較枯燥是真的……也沒辦法……
constructor
雖然說生命周期函數(shù)里沒有明確的包含構(gòu)造函數(shù),這里還是提一下
構(gòu)造函數(shù)是最先運(yùn)行的,同時(shí)這里的操作 應(yīng)該 省時(shí)省力,不應(yīng)該 觸發(fā)任何的副作用,它唯一的作用就是對(duì)變量賦初始值
ngOnChanges
這是第一個(gè)調(diào)動(dòng)的生命周期,也是調(diào)動(dòng)最頻繁的生命周期函數(shù),組件中的變化都會(huì)觸發(fā)這個(gè)函數(shù)的調(diào)用
官方文檔中提到,如果當(dāng)前組件內(nèi)沒有任何 @Input
的話,那么 ngOnChanges
就不會(huì)被調(diào)用。同樣,因?yàn)橥粋€(gè)組件內(nèi)只能存在一個(gè) ngOnChanges
,因此它的功能有點(diǎn)像 useEffect
的依賴數(shù)組中加上了所有的變量,或者對(duì)應(yīng)的 class based component 中的 componentDidUpdate
實(shí)現(xiàn)如下:
export class ServerElementComponent {
@Input('element') aliasElement: ServerElement;
ngOnChanges(changes: SimpleChanges) {
console.log('ngOnChanges in ServerElementComponent');
console.log(changes);
}
}
SimpleChanges
也是從 @angular/core
中導(dǎo)出的,數(shù)據(jù)結(jié)構(gòu)如下:
class SimpleChange {
constructor(previousValue: any, currentValue: any, firstChange: boolean);
previousValue: any;
currentValue: any;
firstChange: boolean;
isFirstChange(): boolean;
}
頁面輸出如下:
同樣的代碼我在 cockpit
和 server-element
都有輸出,但是 cockpit
沒有 @Input
,因此 ngOnChanges
就沒有觸發(fā)
這就是上面中提到的,
當(dāng)前組件內(nèi)沒有任何
@Input
的話,那么ngOnChanges
就不會(huì)被調(diào)用
換言之,ngOnChanges
是針對(duì) @Input
的變化而被調(diào)動(dòng)的
??:ref 不會(huì)引起 ngOnChanges
的調(diào)用,并且,如果被 @Input
綁定的對(duì)象的 reference 沒有變化,也是不會(huì)引起 ngOnChanges
的調(diào)用
??:如果優(yōu)化做的比較好的話,ngOnChanges
能夠有效的提升性能
ngOnInit
ngOnInit
會(huì)在 ngOnChanges
第一次后調(diào)用,如果 ngOnChanges
沒有被觸發(fā),那么 ngOnInit
就是第一個(gè)調(diào)用生命周期函數(shù)。這個(gè)函數(shù)也類似于 componentDidMount
,也就是 useEffect
中為空數(shù)組的實(shí)現(xiàn),同理可證,這也是一個(gè)適合觸發(fā)一個(gè)副作用的地方
具體實(shí)現(xiàn)如下:
ngOnInit() {
console.log('ngOnInit in CockpitComponent');
}
效果如下:
ngDoCheck
ngDoCheck
會(huì)在 ngOnChanges
和 ngOnInit
運(yùn)行后運(yùn)行,不過對(duì)比 ngOnChanges
沒有 @Input
就不會(huì)運(yùn)行的情況,ngDoCheck
只要有變化,就會(huì)運(yùn)行,這個(gè)變化包括 @Input
、對(duì)象等
這也是一個(gè)類似于 componentDidUpdate
的生命周期函數(shù)
因?yàn)?ngDoCheck
會(huì)在每一次變化被感知后運(yùn)行,所以這里也是和添加自定義的變化感知,如:
export class MyComponent implements DoCheck {
@Input() items: any[];
private oldItems: any[];
ngDoCheck() {
if (
this.items &&
this.oldItems &&
this.items.length !== this.oldItems.length
) {
console.log('Items array has changed');
}
this.oldItems = [...this.items];
}
}
這樣的實(shí)現(xiàn)比起直接將數(shù)據(jù)綁定到 @Input()
的優(yōu)點(diǎn)就在于獲取了 previous snapshot 的值,也就類似于 componentDidUpdate(prevProps, prevState, snapshot)
這里面的參數(shù)
但是如果 change 是和 @Input
進(jìn)行綁定的,目前則是可以用 SimpleChanges
中的 firstChange
+ previousValue
+ currentValue
去解決,這樣更加的方便快捷
幾個(gè)使用 ngDoCheck
而不是 ngOnChanges
的場景:
-
檢查更加復(fù)雜的對(duì)象,這一塊之后學(xué)習(xí)到
KeyValueDiffers
再繼續(xù)補(bǔ)全 -
事件觸發(fā),但是沒有值的變化,如鼠標(biāo)點(diǎn)擊事件、鍵盤事件、冒泡事件等
-
異步的情況,如
subscribe
發(fā)生后的情況,這一部分也會(huì)在學(xué)到了異步操作后補(bǔ)全本質(zhì)上來說這也是一個(gè)事件觸發(fā)
ngAfterContentInit
這個(gè)生命周期的調(diào)用是在 ngOnInit
后,ngDoCheck
后調(diào)用,并且只會(huì)被調(diào)用一次
說到 ngAfterContentInit
和 ngOnInit
的區(qū)別就需要簡單的談一下 Angular 的創(chuàng)造順序:
-
父組件先被創(chuàng)建
-
子組件隨后被創(chuàng)建
-
調(diào)用生命周期函數(shù)
ngOnInit
在這個(gè)地方被調(diào)用 -
投射內(nèi)容
ngAfterContentInit
在這里被調(diào)用這時(shí)候如果使用
ng-content
進(jìn)行內(nèi)容的投射,在內(nèi)容透射完畢后,ngAfterContentInit
就會(huì)被調(diào)用以表示當(dāng)前組件已經(jīng)準(zhǔn)備好了,可以完整的被渲染了ng-content
部分的內(nèi)容回顧在這里:[Angular 基礎(chǔ)] - 視圖封裝 & 局部引用 & 父子組件中內(nèi)容傳遞 -
View 層完成初始化
這里就是
ngAfterViewChecked
調(diào)用的地方
從順序和結(jié)構(gòu)上來說:
-
ngOnInit
適合初始化本組件需要的內(nèi)容 -
ngAfterContentInit
適合初始化對(duì) 投射內(nèi)容 具有依賴性的內(nèi)容
這里同樣可以查看一下生命周期調(diào)用時(shí)的輸出結(jié)果,用的是前篇筆記的內(nèi)容,不過只留下了 server-component
中的 ngOnInit
和 ngAfterContentInit
:
可以看到,在 ngOnInit
調(diào)用的時(shí)候,@ContentChild('contentParagraph', { static: true }) paragraph: ElementRef;
這個(gè)內(nèi)容是還沒有投射的,因此輸出 this.paragraph.nativeElement.textContent
就是一個(gè)空的字符串
在 ngAfterContentInit
運(yùn)行時(shí),也就是投射的內(nèi)容已經(jīng)初始化后,Angular 就可以獲得 this.paragraph.nativeElement.textContent
中的內(nèi)容了
ngAfterContentChecked
這個(gè)生命周期函數(shù)會(huì)在每次 Angular 檢查投射的內(nèi)容時(shí)被調(diào)用,基本上是跟著 ngDoCheck
被調(diào)用的
ngAfterViewInit
這個(gè)生命周期函數(shù)檢查的就是 V 層(包括父子組件)是否都被初始化了
這個(gè)函數(shù)也是讓當(dāng)前 VM 層可以訪問其他 V 層
ngAfterViewChecked
同理,這個(gè)生命周期函數(shù)檢查的就是 V 層(包括父子組件)是否都被 check 了文章來源:http://www.zghlxwxcb.cn/news/detail-828160.html
ngOnDestroy
這里就是一個(gè)清理副作用的地方,在運(yùn)行這個(gè)函數(shù)后,當(dāng)前的 Angular 組件就會(huì)被毀滅了文章來源地址http://www.zghlxwxcb.cn/news/detail-828160.html
到了這里,關(guān)于[Angular 基礎(chǔ)] - 生命周期函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!