web-dev-qa-db-fra.com

Quelle est la différence entre markForCheck () et detectChanges ()

Quelle est la différence entre ChangeDetectorRef.markForCheck() et ChangeDetectorRef.detectChanges()?

Je seulement informations trouvées sur SO quant à la différence entre NgZone.run(), mais pas entre ces deux fonctions.

Pour les réponses ne faisant que référence à la documentation, veuillez illustrer quelques scénarios pratiques pour choisir l’un sur l’autre.

134
parliament

De docs:

detectChanges (): void

Vérifie le détecteur de changement et ses enfants.

Cela signifie que s'il y a un cas où quelque chose à l'intérieur de votre modèle (votre classe) a changé mais que cela ne reflète pas la vue, vous devrez peut-être notifier Angular pour détecter ces modifications (détecter les modifications locales). et mettre à jour la vue.

Les scénarios possibles pourraient être:

1- Le détecteur de changement est détaché de la vue (voir detach )

2- Une mise à jour a eu lieu mais elle n’a pas été insérée dans la Angular Zone. Par conséquent, Angular ne le sait pas.

Par exemple, lorsqu'une fonction tierce a mis à jour votre modèle et que vous souhaitez ensuite mettre à jour la vue.

 someFunctionThatIsRunByAThirdPartyCode(){
     yourModel.text = "new text";
 }

Comme ce code est en dehors de la zone angulaire (probablement), vous devez vous assurer de détecter les modifications et de mettre à jour la vue, par exemple:

 myFunction(){
   someFunctionThatIsRunByAThirdPartyCode();

   // Let's detect the changes that above function made to the model which Angular is not aware of.
    this.cd.detectChanges();
 }

NOTE:

Il existe d'autres moyens de faire en sorte que le travail ci-dessus fonctionne. En d'autres termes, il existe d'autres moyens d'introduire ce changement dans le cycle de changements Angular.

** Vous pouvez envelopper cette fonction tierce dans une zone.run:

 myFunction(){
   this.zone.run(this.someFunctionThatIsRunByAThirdPartyCode);
 }

** Vous pouvez envelopper la fonction dans un setTimeout:

myFunction(){
   setTimeout(this.someFunctionThatIsRunByAThirdPartyCode,0);
 }

3- Il y a aussi des cas où vous mettez à jour le modèle une fois le change detection cycle terminé, où dans ces cas vous obtenez cette erreur redoutée:

"L'expression a changé après avoir été cochée";

Cela signifie généralement (à partir du langage Angular2):

J'ai constaté un changement dans votre modèle dû à l'un de mes modes acceptés (événements, demandes XHR, setTimeout et ...), puis j'ai exécuté la détection de changement pour mettre à jour votre vue. Je l'ai terminée, mais il y a eu une autre fonctionne dans votre code qui a mis à jour le modèle à nouveau et je ne veux plus exécuter ma détection de changement car il n’y a plus de vérification fictive comme AngularJS: D et nous devrions utiliser un flux de données à sens unique!

Vous rencontrerez certainement cette erreur: P.

Deux façons de résoudre le problème:

1- Méthode appropriée : assurez-vous que la mise à jour se trouve dans le cycle de détection des modifications (les mises à jour Angular2 sont un flux à sens unique qui se produit une fois, ne mettez pas à jour le modèle après. cela et déplacez votre code à un meilleur endroit/temps).

2- Méthode paresseuse : exécutez detectChanges () après cette mise à jour pour rendre angular2 heureux, ce n'est certainement pas la meilleure façon, mais comme vous l'avez demandé scénarios possibles, c'est l'un d'entre eux.

De cette façon, vous dites: Je sais sincèrement que vous avez effectué la détection des modifications, mais je souhaite que vous le fassiez à nouveau, car je devais mettre à jour quelque chose à la volée une fois la vérification terminée.

3- Placez le code dans un setTimeout, parce que setTimeout est corrigé par zone et exécutera detectChanges une fois terminé.


De la docs

markForCheck() : void

Marque tous les ancêtres de ChangeDetectionStrategy à vérifier.

Cela est surtout nécessaire lorsque ChangeDetectionStrategy de votre composant est OnPush .

OnPush lui-même signifie que vous ne devez exécuter la détection de changement que si l'un de ces événements s'est produit:

1- L'un des @ entrées du composant a été complètement remplacé par une nouvelle valeur, ou tout simplement si la référence de la propriété @Input a complètement changé.

Donc, si ChangeDetectionStrategy de votre composant est OnPush et que vous avez:

   var obj = {
     name:'Milad'
   };

Et puis vous mettez à jour/mute comme:

  obj.name = "a new name";

Cela ne mettra pas à jour la référence obj . Par conséquent, la détection des modifications ne sera pas exécutée. Par conséquent, la vue ne reflète pas la mise à jour/mutation.

Dans ce cas, vous devez indiquer manuellement à Angular de vérifier et de mettre à jour la vue (markForCheck);

Donc si vous avez fait ceci:

  obj.name = "a new name";

Vous devez faire ceci:

  this.cd.markForCheck();

Ci-dessous, une détection de changement serait exécutée:

    obj = {
      name:"a new name"
    };

Ce qui a complètement remplacé l’obj précédent par un nouveau {};

2- Un événement s'est déclenché, comme un clic ou quelque chose de ce genre, ou l'un des composants enfants a émis un événement.

Des événements comme:

  • Cliquez sur
  • Keyup
  • Événements d'abonnement
  • etc.

Donc en bref:

  • Utilisez detectChanges() lorsque vous avez mis à jour le modèle après que angular a détecté ses modifications ou si la mise à jour n'a pas été dans le monde angular.

  • Utilisez markForCheck() si vous utilisez OnPush et que vous contournez ChangeDetectionStrategy en migrant certaines données ou que vous avez mis à jour le modèle dans un set setTimeout ;

182
Milad

La plus grande différence entre les deux est que detectChanges() déclenche la détection de changement, alors que markForCheck() ne déclenche pas la détection de changement.

détecter les changements

Celui-ci est utilisé pour exécuter la détection de changement pour l'arborescence des composants en commençant par le composant sur lequel vous avez déclenché detectChanges(). Ainsi, la détection des modifications sera exécutée pour le composant actuel et tous ses enfants. Angular contient des références à l'arborescence des composants racine dans la variable ApplicationRef et déclenche la détection des modifications de ce composant racine via une méthode d'encapsulation tick():

@Injectable()
export class ApplicationRef_ extends ApplicationRef {
  ...
  tick(): void {
    if (this._runningTick) {
      throw new Error('ApplicationRef.tick is called recursively');
    }

    const scope = ApplicationRef_._tickScope();
    try {
      this._runningTick = true;
      this._views.forEach((view) => view.detectChanges()); <------------------

view voici la vue du composant racine. Il peut y avoir beaucoup de composants racine comme décrit dans le Quelles sont les implications de l’amorçage de plusieurs composants .

@milad a décrit les raisons pour lesquelles vous pourriez potentiellement avoir besoin de déclencher manuellement la détection de changement.

markForCheck

Comme je l'ai dit, ce type ne déclenche pas du tout la détection des changements. Il passe simplement du composant actuel au composant racine vers le haut et met à jour leur état d'affichage sur ChecksEnabled. Voici le code source:

export function markParentViewsForCheck(view: ViewData) {
  let currView: ViewData|null = view;
  while (currView) {
    if (currView.def.flags & ViewFlags.OnPush) {
      currView.state |= ViewState.ChecksEnabled;  <-----------------
    }
    currView = currView.viewContainerParent || currView.parent;
  }
}

La détection de modification réelle pour le composant n'est pas planifiée, mais lorsque cela se produira à l'avenir (dans le cadre du cycle actuel ou suivant du CD), les vues du composant parent seront vérifiées même si elles avaient détaché des détecteurs de modification. Les détecteurs de changement peuvent être détachés en utilisant cd.detach() ou en spécifiant la stratégie de détection de OnPush. Tous les gestionnaires d'événements natifs marquent toutes les vues de composant parent à vérifier.

Cette approche est souvent utilisée dans le hook ngDoCheck cycle de vie. Vous pouvez en lire plus dans le Si vous pensez que ngDoCheck signifie que votre composant est en cours de vérification, lisez cet article .

Voir aussi Tout ce que vous devez savoir sur la détection de changement dans Angular pour plus de détails.

75