59 votes

Pourquoi avons-nous besoin de `ngDoCheck`

Je n'arrive pas à comprendre pourquoi j'ai besoin d' ngDoCheck cycle de vie du crochet, autres que pour la simple notification, en particulier la façon dont l'écriture de code à l'intérieur de cela fait une différence en ce qui concerne la détection de changement. La plupart des exemples que j'ai trouvés montrent inutile d'exemples, comme cette une, avec un tas de fonctionnalité de journalisation.

Aussi, dans les classes générées je ne vois pas qu'il soit utilisé pour autre chose que de la simple notification:

conmponent/wrapper.ngfactory.js

Wrapper_AppComponent.prototype.ngDoCheck = function(view,el,throwOnChange) {
  var self = this;
  var changed = self._changed;
  self._changed = false;
  if (!throwOnChange) {
    if (changed) {
      jit_setBindingDebugInfoForChanges1(view.renderer,el,self._changes);
      self._changes = {};
    }
    self.context.ngDoCheck(); <----------- this calls ngDoCheck on the component
                                           but the result is not used 
                                           anywhere and no params are passed
      }
      return changed;
    };

97voto

Maximus Points 1342

Cet excellent article Si vous pensez que ngDoCheck signifie que votre composant est en cours de vérification lire cet article explique l'erreur en profondeur.

Le contenu de cette réponse est fondée sur l'angle de la version 2.x.x. Pour la plus récente version 4.x.x voir ce post.

Il n'y a rien sur internet sur le fonctionnement interne de détection de changement, donc j'ai dû passer environ une semaine de débogage sources, de sorte que cette réponse sera assez technique sur les détails.

Angulaire de l'application est un arbre de vues (AppView de la classe qui s'est étendu par la Composante spécifique de la classe générée par le compilateur). Chaque point de vue a une détection de changement de mode de vie en cdMode de la propriété. La valeur par défaut de cdMode est ChangeDetectorStatus.CheckAlways, ce qui est cdMode = 2.

Lors d'un changement de cycle de détection exécution, chaque parent vue vérifie si il doit effectuer la détection de changement sur l'enfant de voir ici:

  detectChanges(throwOnChange: boolean): void {
    const s = _scope_check(this.clazz);
    if (this.cdMode === ChangeDetectorStatus.Checked ||
        this.cdMode === ChangeDetectorStatus.Errored)
      return;
    if (this.cdMode === ChangeDetectorStatus.Destroyed) {
      this.throwDestroyedError('detectChanges');
    }
    this.detectChangesInternal(throwOnChange); <---- performs CD on child view

this de points à l' child vue. Donc, si cdMode est ChangeDetectorStatus.Checked=1, la détection de changement est ignorée pour les enfants immédiats et tous ses descendants à cause de cette ligne.

if (this.cdMode === ChangeDetectorStatus.Checked ||
        this.cdMode === ChangeDetectorStatus.Errored)
      return;

Ce changeDetection: ChangeDetectionStrategy.OnPush n'est tout simplement fixe cdMode de ChangeDetectorStatus.CheckOnce = 0, donc après la première exécution de détection de changement de la vue enfant aura son cdMode ensemble de ChangeDetectorStatus.Checked = 1 en raison de ce code:

if (this.cdMode === ChangeDetectorStatus.CheckOnce) 
     this.cdMode = ChangeDetectorStatus.Checked;

Ce qui signifie que la prochaine fois qu'un changement de cycle de détection commence il n'y aura pas de changement de détection effectuée pour la vue enfant.

Il y a quelques options sur la manière d'exécuter la détection de changement de ce point de vue. La première est de changer l'enfant de la vue d' cdMode de ChangeDetectorStatus.CheckOnce, ce qui peut être fait en utilisant this._changeRef.markForCheck() en ngDoCheck du cycle de vie de crochet:

  constructor(private _changeRef: ChangeDetectorRef) {   }

  ngDoCheck() {
    this._changeRef.markForCheck();
  }

Il suffit simplement de change cdMode de la vue actuelle et de ses parents de ChangeDetectorStatus.CheckOnce, alors la prochaine fois que le changement de la détection est effectuée à l'affichage actuel est cochée.

Vérifier un exemple complet d' ici, dans les sources, mais voici l'essentiel:

      constructor(ref: ChangeDetectorRef) {
        setInterval(() => {
          this.numberOfTicks ++
          // the following is required, otherwise the view will not be updated
          this.ref.markForCheck();
          ^^^^^^^^^^^^^^^^^^^^^^^^
        }, 1000);
      }

La deuxième option est de les appeler detectChanges sur la vue elle-même qui va exécuter la détection de changement sur la vue actuelle si cdMode n'est ChangeDetectorStatus.Checked ou ChangeDetectorStatus.Errored. Depuis, onPush angulaire ensembles cdMode de ChangeDetectorStatus.CheckOnce, angulaire va exécuter la détection de changement.

Donc, ngDoCheck ne modifie pas le changement de détection, il est simplement appelé à chaque changé de détection de cycle et c'est le seul travail est de définir la vue actuelle cdMode comme checkOnce, de sorte que lors de la prochaine détection de changement de cycle, il est vérifié pour les modifications. Voir cette réponse pour plus de détails. Si le point de vue actuel de la détection de changement de mode est - checkAlways (activée par défaut si onPush stratégie n'est pas utilisé), ngDoCheck semblent être d'aucune utilité.

20voto

PierreDuc Points 25962

L' DoCheck interface est utilisé pour détecter des changements manuellement lequel l'angle de détection de changement de l'avoir négligé. Une utilisation qui pourrait en être lorsque vous modifiez l' ChangeDetectionStrategy de votre composant, mais vous savez qu'une propriété d'un objet va changer.

Il est plus efficace de vérifier pour ce seul changement, que de laisser l'changeDetector courir à travers l'ensemble de votre composante

let obj = {
  iChange: 'hiii'
}

Si vous utilisez obj.iChange à l'intérieur de votre modèle, angulaire ne le détecte pas si cette valeur est modifiée, parce que la référence de l' obj lui-même ne change pas. Vous avez besoin de mettre en œuvre un ngDoCheck afin de vérifier si la valeur a changé, et demander un detectChanges sur votre composant changeDetector.

À partir de l'angle de la documentation sur DoCheck

Alors que l' ngDoCheck crochet pour détecter quand le nom du héros a changé, il a un effroyable coût. Ce hook est appelé, avec d'énormes fréquence après chaque changement de cycle de détection n'importe où le changement est survenu. Il est appelé à plus de vingt fois dans cet exemple, avant que l'utilisateur ne peut rien faire.

La plupart de ces vérifications sont déclenchées par Angulaire du premier rendu de données non liées ailleurs sur la page. La simple utilisation de la souris dans une autre zone d'entrée déclenche un appel. Relativement peu d'appels révéler de véritables changements aux données pertinentes. Il est clair que notre mise en œuvre doit être très léger, ou l'expérience de l'utilisateur en souffrira.

testé exemple

@Component({
   selector: 'test-do-check',
   template: `
      <div [innerHtml]="obj.changer"></div>
   `, 
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class TestDoCheckComponent implements DoCheck, OnInit {

    public obj: any = {
       changer: 1
    };

    private _oldValue: number = 1;

    constructor(private _changeRef: ChangeDetectorRef){}

    ngOnInit() {
       setInterval(() => {
           this.obj.changer += 1;
       }, 1000);
    }

    ngDoCheck() {
       if(this._oldValue !== this.obj.changer) {
           this._oldValue = this.obj.changer;

           //disable this line to see the counter not moving
           this._changeRef.detectChanges();
       }
    }

}

0voto

Yerkon Points 2383

// ce qui suit est requis, sinon la vue ne sera pas mise à jour

this.ref.markForCheck (); ^^^^^^^^^^^^^^^^^^^^^^^^^^

Bonjour, Maxim @ AngularInDepth.com View est mis à jour sans appeler this.ref.markForCheck () . J'ai testé dans consturctor et ngOnInit. Vérifiez ça

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X