web-dev-qa-db-ja.com

コンポーネントの再レンダリングを強制する方法 Angular 2?

Angular 2でコンポーネントを強制的に再レン​​ダリングする方法デバッグ目的でReduxを使って作業している場合、コンポーネントにビューの再レンダリングを強制したいのですが、可能でしょうか。

142
born2net

レンダリングは変更検出後に行われます。変更の検出を強制するために、変更されたコンポーネントプロパティ値がDOMに伝達されるようにします(そしてブラウザはそれらの変更をビューに表示します)。

  • ApplicationRef.tick() - Angular 1の$rootScope.$digest()と同様 - つまり、完全なコンポーネントツリーをチェックする
  • NgZone.run(callback) - $rootScope.$apply(callback)と同様 - つまり、Angular 2ゾーン内でコールバック関数を評価私は思うが、これがコールバック関数を実行した後に完全なコンポーネントツリーをチェックすることになることは確かではない。
  • ChangeDetectorRef.detectChanges() - $scope.$digest()と同様 - つまり、このコンポーネントとその子のみをチェックする

インポートしてからApplicationRefNgZone、またはChangeDetectorRefをコンポーネントに注入する必要があります。

特定のシナリオでは、1つのコンポーネントだけが変更された場合は最後のオプションをお勧めします。

185
Mark Rajcok

tXは、私が必要とする回避策を見つけた:

  constructor(private zone:NgZone) {
    // enable to for time travel
    this.appStore.subscribe((state) => {
        this.zone.run(() => {
            console.log('enabled time travel');
        });
    });

zone.runを実行すると、コンポーネントは強制的に再レン​​ダリングされます。

44
born2net

ChangeDetectorRefアプローチ

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';

export class MyComponent {

    constructor(private cdr: ChangeDetectorRef) { }

    selected(item: any) {
        if (item == 'Department')
            this.isDepartment = true;
        else
            this.isDepartment = false;
        this.cdr.detectChanges();
    }

}
10
Feng Zhang

ここでの他の答えは、コンポーネントのビューを更新する変更検出サイクルをトリガーするための解決策を提供します(これは完全な再レンダリングと同じではありません)。

次のようにng-templateng-containerおよびViewContainerRefを使用して、コンポーネントを破壊して再初期化する(すべてのライフサイクルフックを呼び出してビューを再構築する)完全な再レンダリングを行うことができます。

<div>
  <ng-container #outlet >
  </ng-container>
</div>

<ng-template #content>
  <child></child>
</ng-template>

#outlet#contentの両方を参照しているコンポーネントでは、アウトレットのコンテンツをクリアして、子コンポーネントの別のインスタンスを挿入できます。

@ViewChild("outlet", {read: ViewContainerRef}) outletRef: ViewContainerRef;
@ViewChild("content", {read: TemplateRef}) contentRef: TemplateRef<any>;

private rerender() {
    this.outletRef.clear();
    this.outletRef.createEmbeddedView(this.contentRef);
}

さらに初期コンテンツをAfterContentInitフックに挿入する必要があります。

ngAfterContentInit() {
    this.outletRef.createEmbeddedView(this.contentRef);
}

完全な実用的な解決策はここにあります https://stackblitz.com/edit/angular-component-rerender

3
Pavel Gurecki

* ngIfを使用してコンポーネントを強制的にリロードします。

コンテナ内のすべてのコンポーネントは、ライフサイクル全体のフックに戻ります。

テンプレートで:

<ng-container *ngIf="_reload">
    components here 
</ng-container>

次に、tsファイルで:

public _reload = true;

private reload() {
    setTimeout(() => this._reload = false);
    setTimeout(() => this._reload = true);
}
2
loonis

通常、ChangeDetectorRef.detectChanges()がこれに最も焦点を絞った方法です。 ApplicationRef.tick()は通常、大胆なアプローチです。

ChangeDetectorRef.detectChanges()を使用するには、コンポーネントの上部にこれが必要です。

import {  ChangeDetectorRef } from '@angular/core';

...その後、通常、コンストラクタに次のように注入するときにエイリアスを作成します。

constructor( private cdr: ChangeDetectorRef ) { ... }

次に、適切な場所で、次のように呼び出します:

this.cdr.detectChanges();

WhereChangeDetectorRef.detectChanges()を呼び出すことは非常に重要です。ライフサイクルと、アプリケーションがどのように機能し、コンポーネントをレンダリングするかを正確に理解する必要があります。宿題を完全に行い、Angularライフサイクルを完全に理解することの代わりになるものはありません。次に、それを理解したら、ChangeDetectorRef.detectChanges()を適切に使用できます(使用する場所を非常に簡単に理解できる場合もあれば、非常に複雑になる場合もあります)。

0
Chris Halcrow