Angular 2 Directive Lifecycle


Angular 2 Directive Lifecycle(ライフサイクル)について説明する前に、Angular 2のDirective(コマンド)とComponent(コンポーネント)の関係について説明します.
Angular 2で定義された命令とコンポーネントインタフェースを見てみましょう.
// angular2/packages/core/src/metadata/directives.ts

export interface Directive {
   selector?: string;  //        HTML        
   inputs?: string[];  //        
   outputs?: string[];  //        
   host?: {[key: string]: string};  //        、   
   providers?: Provider[];  //                
   exportAs?: string;  //     ,          
   queries?: {[key: string]: any};  //          
}

export interface Component extends Directive {
   changeDetection?: ChangeDetectionStrategy;  //              
   viewProviders?: Provider[];     //          (  ContentChildren)      
   moduleId?: string;  //          id,                 
   templateUrl?: string;  //             URL  
   template?: string;  //             
   styleUrls?: string[];  //                    
   styles?: string[];  //          
   animations?: any[];  //         
   encapsulation?: ViewEncapsulation;  //           
   interpolation?: [string, string];  //           ,   "{{" "}}"
   entryComponents?: Array|any[]>;  //             
}

上の図とAngular 2の命令とコンポーネントのインタフェース定義を観察することで、命令とコンポーネントの関係をまとめることができます.コンポーネントは命令に継承され、template、styles、animations、encapsulationなどのUIビューに関連する属性が拡張されます.
次に本題に入り、作成、適用、破棄の手順を記録するAngular 2コマンドのライフサイクルについて説明します.Angular 2は、命令ライフサイクルに関連する一連のフックを提供し、命令ライフサイクルの変化を監視し、関連する操作を実行するのに便利である.Angular 2のすべてのフックを下図に示します.
どうしてそんなにフックが多いのか、驚いたのではないでしょうか.大丈夫です.命令とコンポーネントの違いに基づいてクラスを分けます.
  • 命令アセンブリと共有するフック
  • ngOnChanges
  • ngOnInit
  • ngDoCheck
  • ngOnDestroy

  • アセンブリ特有のフック
  • ngAfterContentInit
  • ngAfterContentChecked
  • ngAfterViewInit
  • ngAfterViewChecked


  • Angular 2指令ライフサイクルフックの役割と呼び出し順序
  • ngOnChanges-データバインディング入力属性の値が変化すると
  • が呼び出される.
  • ngOnInit-最初のngOnChangesの後に
  • を呼び出す.
  • ngDoCheck-カスタムメソッド、値の変更を検出および処理するための
  • ngAfterContentInit-コンポーネントコンテンツの初期化後に
  • を呼び出す.
  • ngAfterContentChecked-コンポーネントは、コンテンツをチェックするたびに
  • を呼び出す.
  • ngAfterViewInit-コンポーネントの対応するビューが初期化された後、
  • が呼び出される.
  • ngAfterViewChecked-コンポーネントはビューをチェックするたびに
  • を呼び出す.
  • ngOnDestroy-命令破棄前に
  • を呼び出す
    Angular 2指令ライフサイクルフック詳細
    命令ライフサイクルフックについて詳しく説明する前に、コンストラクション関数について説明します.
    constructor
    コンポーネントのコンストラクション関数は、すべてのライフサイクルフックの前に呼び出され、主に注入に依存したり、簡単なデータ初期化操作を実行したりするために使用されます.
    import { Component, ElementRef } from '@angular/core';
    
    @Component({
      selector: 'my-app',
      template: `
        

    Welcome to Angular World

    Hello {{name}}

    `, }) export class AppComponent { name: string = ''; constructor(public elementRef: ElementRef) { // this.name = 'Semlinker'; // } }

    ngOnChanges
    データバインディング入力属性の値が変化すると、AngularはngOnChangesメソッドをアクティブに呼び出します.コンポーネントの入力プロパティの変化を監視するために主に使用される、バインドされたプロパティの新しい値と古い値を含むSimpleChangesオブジェクトが得られます.
    app.component.ts
    import { Component } from '@angular/core';
    
    @Component({
      selector: 'my-app',
      template: `
        

    Welcome to Angular World

    `, }) export class AppComponent { }

    child.component.ts
    import { Component, Input, SimpleChanges, OnChanges } from '@angular/core';
    
    @Component({
        selector: 'exe-child',
        template: `
          

    Child Component

    {{ name }}

    ` }) export class ChildComponent implements OnChanges{ @Input() name: string; ngOnChanges(changes: SimpleChanges) { console.dir(changes); } }

    以上のコードの実行後、ブラウザの出力結果:
    ngOnInit
    1回目のngOnChanges実行後に呼び出され、1回のみ呼び出されます.主に、コンポーネントの他の初期化操作を実行したり、コンポーネントが入力した属性値を取得したりするために使用されます.
    import { Component, Input, OnInit } from '@angular/core';
    
    @Component({
        selector: 'exe-child',
        template: `
         

    :{{pname}}

    ` }) export class ChildComponent implements OnInit { @Input() pname: string; // constructor() { console.log('ChildComponent constructor', this.pname); // Output:undefined } ngOnInit() { console.log('ChildComponent ngOnInit', this.pname); // output: pname } }

    ngOnDestory
    命令が破棄される前に、ngOnDestoryメソッドが呼び出されます.イベントリスニングの削除、タイマのクリア、Observableのキャンセルなど、主にクリーンアップ操作を実行するために使用されます.
    @Directive({
        selector: '[destroyDirective]'
    })
    export class OnDestroyDirective implements OnDestroy {
      sayHello: number;
      
      constructor() {
        this.sayHiya = window.setInterval(() => console.log('hello'), 1000);
      }
      
      ngOnDestroy() {
         window.clearInterval(this.sayHiya);
      }
    }

    ngDoCheck
    コンポーネントの入力プロパティが変化すると、ngDoCheckメソッドがトリガーされます.この方法を使用して、検出ロジックをカスタマイズできます.私たちの変化検出の速度を加速させるためにも使用できます.
    ngAfterContentInit
    コンポーネントがng-content命令を使用する場合、Angularは外部コンテンツをビューに配置した後に使用します.主に、@ContentChildまたは@ContentChildrenプロパティエクスプローラでクエリーされたコンテンツビュー要素を取得するために使用されます.
    使用例については、「Angular 2 ContentChild&ContentChildren」を参照してください.
    ngAfterContentChecked
    コンポーネントがng-content命令を使用する場合、Angularは、外部コンテンツのバインディングが検出されるか、または変化するたびに呼び出される.
    ngAfterViewInit
    コンポーネントの対応するビューが初期化された後に呼び出され、主に@ViewChildまたは@ViewChildrenプロパティエクスプローラでクエリーされたビュー要素を取得するために使用されます.
    使用例については、「Angular 2 ViewChild&ViewChildren」を参照してください.
    ngAfterViewChecked
    コンポーネントがビューをチェックするたびに呼び出されます
    Angular 2 LifecycleHooks、SimpleChangesなどの関連インタフェース
    LifecycleHooksインタフェース
    export interface OnChanges { ngOnChanges(changes: SimpleChanges): void; }
    
    export interface OnInit { ngOnInit(): void; }
    
    export interface DoCheck { ngDoCheck(): void; }
    
    export interface OnDestroy { ngOnDestroy(): void; }
    
    export interface AfterContentInit { ngAfterContentInit(): void; }
    
    export interface AfterContentChecked { ngAfterContentChecked(): void; }
    
    export interface AfterViewInit { ngAfterViewInit(): void; }
    
    export interface AfterViewChecked { ngAfterViewChecked(): void; }

    SimpleChange
    //         
    export class SimpleChange {
      constructor(public previousValue: any, 
          public currentValue: any, 
          public firstChange: boolean) {}
          
      //          
      isFirstChange(): boolean { return this.firstChange; }
    }

    SimpleChanges
    export interface SimpleChanges { [propName: string]: SimpleChange; }

    Angular 2 Viewの詳細
    Angular 2のビューは、次の3つのセクションで構成されています.
  • Elements-要素
  • Bindings-バインド
  • Events-イベント
  • Angular 2 TemplateRef&ViewContainerRefの記事では、Angular 2がサポートするView(ビュー)タイプについて説明します.
  • Embedded Views-Template要素
  • Host Views-Componentコンポーネント
  • 次に、コンポーネントに対応するHost Viewsを分析します.具体的な例は次のとおりです.
    child.component.ts
    import { Component, Input, SimpleChanges, OnChanges, AfterViewChecked } from '@angular/core';
    
    @Component({
        selector: 'exe-child',
        template: `
          

    Child Component

    {{ name }}

    ` }) export class ChildComponent implements OnChanges, AfterViewChecked{ @Input() name: string; ngOnChanges(changes: SimpleChanges) { console.dir(changes); setTimeout(() => { this.name = 'exe-child-component-1' }, 0); } ngAfterViewChecked() { console.log('ngAfterViewChecked hook has been called'); } }

    app.component.ts
    import { Component } from '@angular/core';
    
    @Component({
      selector: 'my-app',
      template: `
        

    Welcome to Angular World

    `, }) export class AppComponent { }

    以上のコードの実行後、ブラウザの出力結果:
    次にChildComponentコンポーネントを分析し、まずコンパイル後のcomponentを見てみましょう.ngfactory.jsファイル.
    ChildComponent/component.ngfactory.jsコードクリップ:
    function View_ChildComponent0(viewUtils,parentView,parentIndex,parentElement) {
      var self = this;
      ...
      self._expr_7 = jit_CD_INIT_VALUE5;
    }
    
    /*
    *            
    * ChildComponent - template
    * 

    Child Component

    *

    {{ name }}

    */ View_ChildComponent0.prototype.createInternal = function(rootSelector) { var self = this; var parentRenderNode = self.renderer.createViewRoot(self.parentElement); ... // (1) p -

    Child Component

    self._el_1 = jit_createRenderElement6(self.renderer,parentRenderNode, 'p', jit__object_Object_7,self.debug(1,1,6)); // , - 'Child Component' self._text_2 = self.renderer.createText(self._el_1,'Child Component', self.debug(2,1,9)); // (2) p -

    {{ name }}

    self._el_4 = jit_createRenderElement6(self.renderer,parentRenderNode, 'p', jit__object_Object_7,self.debug(4,2,6)); self._text_5 = self.renderer.createText(self._el_4,'',self.debug(5,2,9)); self.init(null,(self.renderer.directRenderer? null: [...] ),null); return null; }; // View_ChildComponent0.prototype.detectChangesInternal = function(throwOnChange) { var self = this; self.debug(5,2,9); var currVal_7 = jit_inlineInterpolate8(1,'',self.context.name,''); if (jit_checkBinding9(throwOnChange,self._expr_7,currVal_7)) { self.renderer.setText(self._text_5,currVal_7); self._expr_7 = currVal_7; } };

    ChildComponent/wrapper.ngfactory.jsコードクリップ:
    function Wrapper_ChildComponent() {
      var self = this;
      self._changed = false;
      self._changes = {}; //   Changes  
      self.context = new jit_ChildComponent0();
      self._expr_0 = jit_CD_INIT_VALUE1; // {}
    }
    
    Wrapper_ChildComponent.prototype.ngOnDestroy = function() { };
    
    Wrapper_ChildComponent.prototype.check_name =function(currValue,
      throwOnChange, forceUpdate) {
      var self = this;
      //        ,jit_checkBinding2     looseIdentical(oldValue, newValue)
      //       (===)
      if ((forceUpdate || jit_checkBinding2(throwOnChange,self._expr_0,currValue))) {
        self._changed = true;
        self.context.name = currValue;
        //   name   SimpleChange  
        self._changes['name'] = new jit_SimpleChange3(self._expr_0,currValue);
        self._expr_0 = currValue;
      }
    };
    
    
    Wrapper_ChildComponent.prototype.ngDoCheck = function(view,el,throwOnChange) {
      var self = this;
      var changed = self._changed;
      self._changed = false;
      if (!throwOnChange) { if (changed) {
        self.context.ngOnChanges(self._changes);
        jit_setBindingDebugInfoForChanges4(view.renderer,el,self._changes);
        self._changes = {};
      } }
      return changed;
    };
     ...
    return Wrapper_ChildComponent
    })
    

    話があるんだ
    1.命令ライフサイクルフックを登録する場合、必ず対応するインタフェースを実現しますか?
    命令ライフサイクルフックを登録する場合、対応するインタフェースを実現する必要はありません.インタフェースは、ライフサイクルフックを登録するときに、フックの名前を書き間違え、実行時に異常を投げ出さない可能性がありますが、ページ表示は予想される効果ではありません.そのため、読者はやはりこの開発規範を守ることをお勧めします.また、TypeScriptで定義されているインタフェースは、ES 5関連コードの生成をコンパイルせず、コンパイルフェーズの検証にのみ使用されることに注意してください.
    未完待機