2016-11-27 13 views
11

データテーブルコンポーネント(angular2-data-table)を使用して、プロジェクトをAngularの従来の変更検出からOnPushに変更し、最適化されたレンダリング速度を得ました。Angular2 ngFor ArrayMutationsのOnPush変更検出

新しい変更検出ストラテジが実装された後、オブジェクトのプロパティの更新などのデータオブジェクトが変更されたときに、テーブルが更新されていないことを参照するバグがファイルされました。参照:https://github.com/swimlane/angular2-data-table/issues/255。インライン編集やストック・ティッカーのような大規模データ・コレクション内の単一のプロパティーへの外部データ変更などのために、このタイプのニーズを強力に使用することができます。問題を解決するための努力において

は、我々はtrackByPropと呼ばれるカスタムtrackByプロパティチェッカーを追加しました。参考:commit。残念ながら、この解決策では問題は解決しませんでした。

ライブリロード中のdemo pageでは、上記のコミットで参照されているデモが表示されますが、これをクリックすると変更検出がトリガーされるまでテーブルは更新されません。

部品の構造のようなものです。これらの構成要素のすべてがOnPushを実装

Table > Body > Row Group > Row > Cell

。私はhereのようにページの再計算をトリガする行セッタのgetters/settersを使用しています。

このパターンを実装している人には、変更の検出をOnPush残しておきたいのですが、複数のコンシューマを持つオープンソースプロジェクトでは、画面上に表示される行の値に対して何らかのカスタムチェック機能を主張できます。

trackByは、行のセル値の変化の検出をトリガされていないと述べたことすべてが、これを実現する最良の方法は何ですか?

+0

質問は、問題を再現することを可能にするコードを含める必要があります。 –

答えて

15

Angular2変更検出では、配列またはオブジェクトの内容がチェックされません。

ハックの回避策は、単に変異

this.myArray.push(newItem); 
this.myArray = this.myArray.slice(); 

この方法this.myArrayは異なる配列のインスタンスを参照し、角度変化を認識した後、配列のコピーを作成することです。

別のアプローチは、(オブジェクト用)IterableDiffer(配列の場合)またはKeyValueDifferを使用することです

// inject a differ implementation 
constructor(differs: KeyValueDiffers) { 
    // store the initial value to compare with 
    this.differ = differs.find({}).create(null); 
} 

@Input() data: any; 

ngDoCheck() { 
    var changes = this.differ.diff(this.data); // check for changes 
    if (changes && this.initialized) { 
    // do something if changes were found 
    } 
} 

も参照してくださいhttps://github.com/angular/angular/blob/14ee75924b6ae770115f7f260d720efa8bfb576a/modules/%40angular/common/src/directives/ng_class.ts#L122

+0

クリックのようなイベントを呼び出すまで、 'ngDoCheck'は実行されていません。また、 '* ngFor'にカスタムトラッキングが既にあることに気付きました。なぜこれを検出できないのでしょうか? https://github.com/angular/angular/blob/master/modules/%40angular/common/src/directives/ng_for.ts#L113 – amcdnl

+0

私はRxを次のように使って調査していました:http://stackoverflow.com/questions/32683488/rxjs-observing-object-updates-and-changes – amcdnl

+0

上記のように、問題は再現できるだけの十分な情報を提供すべきです。私の答えはヒップからのシュートだった。再現するPlunkerが役に立ちます。おそらくそれはゾーンの問題です。 –

2

あなたはChangeDetectorRefからmarkForCheckメソッドを使用する場合があります。


私は多くのデータが含まれており、すべての変更検出サイクルで再確認し、それらのすべてのオプションではありませんコンポーネントを持っている同様の問題を持っています。しかし、我々はURLからいくつかのプロパティを見て、私たちは私たちのonPushビューが(自動的に)に更新されていないと、それに応じてビューで物事を変更すると。あなたのコンストラクタでそう

changeDetectorRefのインスタンスを取得するためにDIを使用します。 constructor(private changeDetectorRef: ChangeDetectorRef)

そして、あなたはchangeDetectionをトリガするために必要な場所: this.changeDetectorRef.markForCheck();

+0

私は親ページでこれを試しても結果はありませんでした。おそらく、それをレンダリングするコンポーネントレベルで行う必要がありますが、その時点で私は何も変更されていることを知らない:S – amcdnl

+0

プロパティを変更するカスタムAPIのいくつかの並べ替えを行うことができますか?しかし、APIの観点からはそれほど良いことではありません。 – amcdnl

1

私も最適化するために同様の問題に直面しました私のアプリのパフォーマンスは、私はchangeDetection.OnPush戦略を使用しなければならなかった。だから私は、私の親コンポーネントだけでなく、私の子コンポーネントのコンストラクタの両方にchangeDetectorRef子コンポーネントで同様

export class Parentcomponent{ 
     prop1; 

     constructor(private _cd : ChangeDetectorRef){ 
      } 
     makeXHRCall(){ 
     prop1 = ....something new value with new reference; 
     this._cd.markForCheck(); // To force angular to trigger its change detection now 
     } 
    } 

のインスタンスを、それを注射し

export class ChildComponent{ 
    @Input myData: myData[]; 
    constructor(private _cd : ChangeDetectorRef){ 
      } 
     changeInputVal(){ 
     this.myData = ....something new value with new reference; 
     this._cd.markForCheck(); // To force angular to trigger its change detection now 
     } 
    } 
changeDetectorRef のインスタンスを注入し

角度変化検出はすべての非同期機能でトリガされます: -

  • クリック、送信、マウスオーバーなどのDOMイベント。
  • 任意のXHRコール
  • だから、などのsetTimeout()、のような任意のタイマー

、アプリ遅くなり、この種の我々は、マウスをドラッグしている場合でも、角度はchangeDetectionをトリガーしたため。複数のコンポーネントにまたがる複雑なアプリケーションでは、角度がこのツリーの親子変化検出戦略を持つので、これは大きなパフォーマンスのボトルネックになる可能性があります。 これを避けるには、これはOnPush戦略を使用し、角度の変化検出を強制的にトリガーして基準変更があることがわかった方が良いです。

第2に、OnPush戦略では、オブジェクトの参照値に変化があったときだけ変化を引き起こすことに非常に注意しなければなりません。例えばのために

: -

obj = { a:'value1', b:'value2'}' 
    obj.a = value3; 

「」 'objの中での変化があるかもしれませんが、objはまだ同じ参照を指して、その角度変化の検出は、ここでトリガされませんのプロパティ値(もしない限り力それに); 新しい参照を作成するには、オブジェクトを別のオブジェクトに複製し、それに応じてそのプロパティを割り当てる必要があります。さらなる理解のために

、Immmutableデータ構造について読む、変化検出here