Кутне куке животног циклуса: нгОнЦхангес, нгОнИнит и још много тога

Зашто су нам потребне куке за животни циклус?

Савремени фронт-енд оквири премештају апликацију из стања у стање. Подаци подстичу ове исправке. Ове технологије ступају у интеракцију са подацима који заузврат прелазе у стање. Са сваком променом државе, постоје многи специфични тренуци када одређена имовина постаје доступна.

У једном случају предложак је можда спреман, а у другом ће се пренос података завршити. Кодирање за сваку инстанцу захтева средства за откривање. Куке животног циклуса одговарају на ову потребу. Модерни фронт-енд оквири пакују се у разне куке животног циклуса. Угаона није изузетак

Објашњене куке животног циклуса

Куке животног циклуса су временске методе. Они се разликују у томе када и зашто погубљују. Откривање промена покреће ове методе. Они се извршавају у зависности од услова тренутног циклуса. Угаони покрети непрестано откривају промене на својим подацима. Куке за животни циклус помажу у управљању његовим ефектима.

Важан аспект ових кука је редослед извршења. Никад не одступа. Они се извршавају на основу предвидљиве серије догађаја оптерећења произведених из циклуса детекције. То их чини предвидљивим.

Нека средства су доступна само након извршавања одређене куке. Наравно, кука се извршава само под одређеним условима постављеним у тренутном циклусу откривања промена.

Овај чланак представља куке животног циклуса по редоследу њиховог извршавања (ако се сви извршавају). Одређени услови заслужују активацију удице. Постоји неколико који извршавају само једном након иницијализације компоненти.

Све методе животног циклуса су доступне у @angular/core. Иако није потребно, Ангулар препоручује употребу сваке куке. Ова пракса доводи до бољих порука о грешкама у вези са компонентом.

Налог извршења кука за животни циклус

нгОнЦхангес

ngOnChangesокидачи након модификације @Inputвезаних чланова класе. Подаци које @Input()декоратер веже потичу из спољног извора. Када спољни извор измени те податке на препознатљив начин, он поново пролази кроз @Inputсвојство.

Са овом исправком, ngOnChangesодмах се активира. Такође се активира приликом иницијализације улазних података. Кука прима један опционални параметар типа SimpleChanges. Ова вредност садржи информације о промењеним својствима везаним за унос.

import { Component, Input, OnChanges } from '@angular/core'; @Component({ selector: 'app-child', template: ` 

Child Component

TICKS: {{ lifecycleTicks }}

DATA: {{ data }}

` }) export class ChildComponent implements OnChanges { @Input() data: string; lifecycleTicks: number = 0; ngOnChanges() { this.lifecycleTicks++; } } @Component({ selector: 'app-parent', template: `

ngOnChanges Example

` }) export class ParentComponent { arbitraryData: string = 'initial'; constructor() { setTimeout(() => { this.arbitraryData = 'final'; }, 5000); } }

Резиме: ПарентЦомпонент веже улазне податке за ЦхилдЦомпонент. Компонента прима ове податке путем свог@Inputсвојства. ngOnChangesватре. Након пет секунди,setTimeoutактивирасеповратни позив. ПарентЦомпонент мутира извор података својства ЦхилдЦомпонент-а повезаног са уносом. Нови подаци пролазе кроз својство уноса. ngOnChangesпожари још једном.

нгОнИнит

ngOnInitактивира се једном приликом иницијализације @Inputсвојстава инпут-боунд ( ) компоненте . Следећи пример ће изгледати слично последњем. Кука се не активира јер ЦхилдЦомпонент прима улазне податке. Уместо тога, активира се одмах након што се подаци прикажу у предлошку ЦхилдЦомпонент.

import { Component, Input, OnInit } from '@angular/core'; @Component({ selector: 'app-child', template: ` 

Child Component

TICKS: {{ lifecycleTicks }}

DATA: {{ data }}

` }) export class ChildComponent implements OnInit { @Input() data: string; lifecycleTicks: number = 0; ngOnInit() { this.lifecycleTicks++; } } @Component({ selector: 'app-parent', template: `

ngOnInit Example

` }) export class ParentComponent { arbitraryData: string = 'initial'; constructor() { setTimeout(() => { this.arbitraryData = 'final'; }, 5000); } }

Резиме: ПарентЦомпонент веже улазне податке за ЦхилдЦомпонент. ЦхилдЦомпонент прима ове податке путем свог@Inputсвојства. Подаци се приказују у предлошку. ngOnInitватре. Након пет секунди,setTimeoutактивирасеповратни позив. ПарентЦомпонент мутира извор података својства ЦхилдЦомпонент-а повезаног са уносом. нгОнИнит НЕ ПАЛИ.

ngOnInitје једнократна удица. Његова иницијатива је једина брига.

нгДоЦхецк

ngDoCheckпали се са сваким циклусом откривања промена. Детекција промена угаоних трчања се често мења. Ако извршите било коју радњу, циклус ће се покренути. ngDoCheckпожара са овим циклусима. Користите га опрезно. Може да створи проблеме са перформансама када се погрешно примени.

ngDoCheckомогућава програмерима да ручно проверавају своје податке. Они могу условно покренути нови датум пријаве. Заједно са ChangeDetectorRefпрограмерима могу креирати сопствене чекове за откривање промена.

import { Component, DoCheck, ChangeDetectorRef } from '@angular/core'; @Component({ selector: 'app-example', template: ` 

ngDoCheck Example

DATA: {{ data[data.length - 1] }}

` }) export class ExampleComponent implements DoCheck { lifecycleTicks: number = 0; oldTheData: string; data: string[] = ['initial']; constructor(private changeDetector: ChangeDetectorRef) { this.changeDetector.detach(); // lets the class perform its own change detection setTimeout(() => { this.oldTheData = 'final'; // intentional error this.data.push('intermediate'); }, 3000); setTimeout(() => { this.data.push('final'); this.changeDetector.markForCheck(); }, 6000); } ngDoCheck() { console.log(++this.lifecycleTicks); if (this.data[this.data.length - 1] !== this.oldTheData) { this.changeDetector.detectChanges(); } } }

Обратите пажњу на конзолу у односу на екран. Подаци напредују до „средњег нивоа“ пре замрзавања. Током овог периода догађају се три круга откривања промена, како је назначено у конзоли. Још један круг откривања промена се дешава када се „коначни“ помера до краја this.data. Тада се дешава последњи круг детекције промена. Процјена изјаве иф утврђује да нису потребна ажурирања приказа.

Резиме: Класа се покреће након два круга откривања промена. Конструктор класе се покрећеsetTimeoutдва пута. После три секунде, првиsetTimeoutпокретачи откривају промене. ngDoCheckозначава екран за ажурирање. Три секунде касније, другиsetTimeoutпокретачи откривају промене. Нису потребна ажурирања приказа према процениngDoCheck.

Упозорење

Пре него што наставите, научите разлику између ДОМ садржаја и приказа ДОМ (ДОМ је скраћеница од Модел објекта документа).

Садржај ДОМ дефинише иннерХТМЛ елемената директиве. Супротно томе, приказ ДОМ је предложак компоненте који искључује било који ХТМЛ предложак угнежђен унутар директиве. За боље разумевање погледајте овај пост на блогу.

нгАфтерЦонтентИнит

ngAfterContentInitактивира се након покретања садржаја компоненте ДОМ (учитава се први пут). Чекање на @ContentChild(ren)упите је примарни случај употребе удице.

@ContentChild(ren)упити дају референце на елементе за садржај ДОМ. Као такви, доступни су тек након учитавања садржаја ДОМ-а. Отуда се зашто ngAfterContentInitи његов пандан ngAfterContentCheckedкористе.

import { Component, ContentChild, AfterContentInit, ElementRef, Renderer2 } from '@angular/core'; @Component({ selector: 'app-c', template: ` 

I am C.

Hello World!

` }) export class CComponent { } @Component({ selector: 'app-b', template: `

I am B.

` }) export class BComponent implements AfterContentInit { @ContentChild("BHeader", { read: ElementRef }) hRef: ElementRef; @ContentChild(CComponent, { read: ElementRef }) cRef: ElementRef; constructor(private renderer: Renderer2) { } ngAfterContentInit() { this.renderer.setStyle(this.hRef.nativeElement, 'background-color', 'yellow') this.renderer.setStyle(this.cRef.nativeElement.children.item(0), 'background-color', 'pink'); this.renderer.setStyle(this.cRef.nativeElement.children.item(1), 'background-color', 'red'); } } @Component({ selector: 'app-a', template: `

ngAfterContentInit Example

I am A.

BComponent Content DOM

` }) export class AComponent { }

Резултати @ContentChildупита су доступни на ngAfterContentInit. Renderer2ажурира садржај ДОМ БЦомпонента који садржи h3ознаку и ЦЦомпонент. Ово је чест пример пројекције садржаја.

Резиме: Приказивање започиње са АЦомпонент. Да би се завршио, АЦомпонент мора приказати БЦомпонент. БЦомпонент пројектује садржај угнежђен у његов елемент крозелемент. ЦЦомпонент је део пројектованог садржаја. Пројектовани садржај завршава приказивање. ngAfterContentInitватре. БЦомпонент завршава приказивање. АЦомпонент завршава приказивање. ngAfterContentInitвише неће пуцати.

нгАфтерЦонтентЦхецкед

ngAfterContentCheckedактивира се након сваког циклуса откривања промена циљајући садржај ДОМ. Ово омогућава програмерима да олакшају како ДОМ садржаја реагује на откривање промена. ngAfterContentCheckedмогу се често активирати и изазвати проблеме са перформансама ако се лоше примене.

ngAfterContentCheckedактивира се и током фаза иницијализације компоненте. Долази одмах након ngAfterContentInit.

import { Component, ContentChild, AfterContentChecked, ElementRef, Renderer2 } from '@angular/core'; @Component({ selector: 'app-c', template: ` 

I am C.

Hello World!

` }) export class CComponent { } @Component({ selector: 'app-b', template: `

I am B.

CLICK ` }) export class BComponent implements AfterContentChecked { @ContentChild("BHeader", { read: ElementRef }) hRef: ElementRef; @ContentChild(CComponent, { read: ElementRef }) cRef: ElementRef; constructor(private renderer: Renderer2) { } randomRGB(): string { return `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)})`; } ngAfterContentChecked() { this.renderer.setStyle(this.hRef.nativeElement, 'background-color', this.randomRGB()); this.renderer.setStyle(this.cRef.nativeElement.children.item(0), 'background-color', this.randomRGB()); this.renderer.setStyle(this.cRef.nativeElement.children.item(1), 'background-color', this.randomRGB()); } } @Component({ selector: 'app-a', template: `

ngAfterContentChecked Example

I am A.

BComponent Content DOM

` }) export class AComponent { }

Ово се тешко разликује од ngAfterContentInit. Пуко је додато БЦомпоненту. Његов клик узрокује петљу откривања промена. Ово активира куку како је назначено случајним одабиром background-color.

Резиме: Приказивање започиње са АЦомпонент. Да би се завршио, АЦомпонент мора приказати БЦомпонент. БЦомпонент пројектује садржај угнежђен у његов елемент крозелемент. ЦЦомпонент је део пројектованог садржаја. Пројектовани садржај завршава приказивање. ngAfterContentCheckedватре. БЦомпонент завршава приказивање. АЦомпонент завршава приказивање. ngAfterContentCheckedможе поново да се активира откривањем промена.

нгАфтерВиевИнит

ngAfterViewInitактивира се једном након завршетка иницијализације приказа ДОМ. Поглед се увек учитава одмах након садржаја. ngAfterViewInitчека на @ViewChild(ren)решавање упита. Ови елементи се траже из истог погледа на компоненту.

У доњем примеру се тражи h3заглавље БЦомпонент . ngAfterViewInitизвршава се чим су доступни резултати упита.

import { Component, ViewChild, AfterViewInit, ElementRef, Renderer2 } from '@angular/core'; @Component({ selector: 'app-c', template: ` 

I am C.

Hello World!

` }) export class CComponent { } @Component({ selector: 'app-b', template: `

I am B.

` }) export class BComponent implements AfterViewInit { @ViewChild("BStatement", { read: ElementRef }) pStmt: ElementRef; constructor(private renderer: Renderer2) { } ngAfterViewInit() { this.renderer.setStyle(this.pStmt.nativeElement, 'background-color', 'yellow'); } } @Component({ selector: 'app-a', template: `

ngAfterViewInit Example

I am A.

BComponent Content DOM

` }) export class AComponent { }

Renderer2мења боју позадине заглавља БЦомпонент. То указује на то да је елемент прегледа успешно затражен захваљујући ngAfterViewInit.

Summary: Rendering starts with AComponent. For it to finish, AComponent must render BComponent. BComponent projects content nested in its element through the element. CComponent is part of the projected content. The projected content finishes rendering. BComponent finishes rendering. ngAfterViewInit fires. AComponent finishes rendering. ngAfterViewInit will not fire again.

ngAfterViewChecked

ngAfterViewChecked fires after any change detection cycle targeting the component’s view. The ngAfterViewChecked hook lets developers facilitate how change detection affects the view DOM.

import { Component, ViewChild, AfterViewChecked, ElementRef, Renderer2 } from '@angular/core'; @Component({ selector: 'app-c', template: ` 

I am C.

Hello World!

` }) export class CComponent { } @Component({ selector: 'app-b', template: `

I am B.

CLICK ` }) export class BComponent implements AfterViewChecked { @ViewChild("BStatement", { read: ElementRef }) pStmt: ElementRef; constructor(private renderer: Renderer2) { } randomRGB(): string { return `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)})`; } ngAfterViewChecked() { this.renderer.setStyle(this.pStmt.nativeElement, 'background-color', this.randomRGB()); } } @Component({ selector: 'app-a', template: `

ngAfterViewChecked Example

I am A.

BComponent Content DOM

` }) export class AComponent { }

Summary: Rendering starts with AComponent. For it to finish, AComponent must render BComponent. BComponent projects content nested in its element through the element. CComponent is part of the projected content. The projected content finishes rendering. BComponent finishes rendering. ngAfterViewChecked fires. AComponent finishes rendering. ngAfterViewChecked may fire again through change detection.

Clicking the element initiates a round of change detection. ngAfterContentChecked fires and randomizes the background-color of the queried elements each button click.

ngOnDestroy

ngOnDestroy fires upon a component’s removal from the view and subsequent DOM. This hook provides a chance to clean up any loose ends before a component’s deletion.

import { Directive, Component, OnDestroy } from '@angular/core'; @Directive({ selector: '[appDestroyListener]' }) export class DestroyListenerDirective implements OnDestroy { ngOnDestroy() { console.log("Goodbye World!"); } } @Component({ selector: 'app-example', template: ` 

ngOnDestroy Example

TOGGLE DESTROY

I can be destroyed!

` }) export class ExampleComponent { destroy: boolean = true; toggleDestroy() { this.destroy = !this.destroy; } }

Summary: The button is clicked. ExampleComponent’s destroy member toggles false. The structural directive *ngIf evaluates to false. ngOnDestroy fires. *ngIf removes its host . This process repeats any number of times clicking the button to toggle destroy to false.

Conclusion

Remember that certain conditions must be met for each hook. They will always execute in order of each other regardless. This makes hooks predictable enough to work with even if some do not execute.

With lifecycle hooks, timing the execution of a class is easy. They let developers track where change detection is occurring and how the application should react. They stall for code that requires load-based dependencies available only after sometime.

Животни циклус компоненте карактерише савремене предње оквире. Ангулар поставља свој животни циклус пружајући горе поменуте куке.

Извори

  • Ангулар Теам. „Куке за животни циклус“. Гоогле . Приступљено 02. јуна 2018
  • Гечев, Минко. „ВиевЦхилдрен анд ЦонтентЦхилдрен ин Ангулар“. Приступљено 02. јуна 2018

Ресурси

  • Угаона документација
  • Ангулар ГитХуб Репоситори
  • Куке животног циклуса у дубини