Quelle est la différence entre ChangeDetectorRef.markForCheck()
et ChangeDetectorRef.detectChanges()
?
Je n'ai trouvé que des informations sur SO quant à la différence entre NgZone.run()
, mais pas entre ces deux fonctions.
Pour les réponses avec uniquement une référence au document, veuillez illustrer quelques scénarios pratiques pour choisir l'un par rapport à l'autre.
angular
angular2-changedetection
parlement
la source
la source
Réponses:
À partir de la documentation:
Cela signifie que s'il y a un cas où quelque chose à l'intérieur de votre modèle (votre classe) a changé mais qu'il n'a pas reflété la vue, vous devrez peut-être notifier Angular pour détecter ces changements (détecter les changements locaux) et mettre à jour la vue.
Les scénarios possibles pourraient être:
1- Le détecteur de changement est détaché de la vue (voir détacher )
2- Une mise à jour a eu lieu mais elle n'a pas été dans la zone angulaire, par conséquent, Angular ne le sait pas.
Comme lorsqu'une fonction tierce a mis à jour votre modèle et que vous souhaitez mettre à jour la vue après cela.
Étant donné que ce code est en dehors de la zone d'Angular (probablement), vous devez probablement vous assurer de détecter les modifications et de mettre à jour la vue, ainsi:
REMARQUE :
Il existe d'autres façons de faire fonctionner ci-dessus, en d'autres termes, il existe d'autres façons d'apporter ce changement à l'intérieur du cycle de changement angulaire.
** Vous pouvez envelopper cette fonction tierce dans un zone.run:
** Vous pouvez envelopper la fonction dans un setTimeout:
3- Il y a aussi des cas où vous mettez à jour le modèle une fois que le
change detection cycle
est terminé, où dans ces cas vous obtenez cette erreur redoutée:"L'expression a changé après avoir été vérifiée";
Cela signifie généralement (du langage Angular2):
J'ai vu un changement dans votre modèle qui a été causé par l'un de mes moyens acceptés (événements, requêtes XHR, setTimeout, et ...) puis j'ai exécuté ma détection de changement pour mettre à jour votre vue et je l'ai terminé, mais il y en a eu un autre fonction 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 sale comme AngularJS: D et nous devrions utiliser un flux de données à sens unique!
Vous rencontrerez certainement cette erreur: P.
Quelques façons de résoudre ce problème:
1- Bonne manière : assurez-vous que la mise à jour est dans le cycle de détection des changements (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 vers un meilleur endroit / heure).
2- Méthode paresseuse : lancez detectChanges () après cette mise à jour pour rendre angular2 heureux, ce n'est certainement pas la meilleure façon, mais comme vous avez demandé quels sont les scénarios possibles, c'est l'un d'entre eux.
De cette façon, vous dites: je sais sincèrement que vous avez exécuté la détection des modifications, mais je veux que vous le refassiez car j'ai dû mettre à jour quelque chose à la volée après avoir terminé la vérification.
3- Mettez le code dans un
setTimeout
, car ilsetTimeout
est patché par zone et s'exécutera unedetectChanges
fois terminé.À partir des documents
Ceci est principalement nécessaire lorsque la ChangeDetectionStrategy de votre composant est OnPush .
OnPush lui-même signifie, n'exécutez la détection de changement que si l'un de ces événements s'est produit:
1- L'une des @inputs du composant a été complètement remplacée par une nouvelle valeur, ou 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:
Et puis vous le mettez à jour / le mutez comme:
Cela ne mettra pas à jour la référence obj , donc la détection de changement ne fonctionnera pas, donc la vue ne reflète pas la mise à jour / la 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:
Vous devez faire ceci:
Au contraire, ci-dessous entraînerait l'exécution d'une détection de changement:
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 comme ça ou l'un des composants enfants a émis un événement.
Des événements comme:
Donc en bref:
À utiliser
detectChanges()
lorsque vous avez mis à jour le modèle après que Angular a exécuté sa détection de changement, ou si la mise à jour n'a pas du tout été dans le monde angulaire.À utiliser
markForCheck()
si vous utilisez OnPush et que vous contournez le enChangeDetectionStrategy
faisant muter certaines données ou si vous avez mis à jour le modèle dans un setTimeout ;la source
detectChanges
vue des mises à jour. Voir cette explication détaillée .this.cdMode === ChangeDetectorStatus.Checked
elle ne met pas à jour la vue, c'est pourquoi vous utiliseriez markForCheck.detectChanges
. Et il n'y a pascdMode
dans Angular4.x.x
. J'écris à ce sujet dans mon article. Content que tu aies aimé. N'oubliez pas que vous pouvez le recommander sur support ou me suivre :)La plus grande différence entre les deux est que
detectChanges()
déclenche réellement la détection des changements, maismarkForCheck()
ne déclenche pas la détection des changements.detectChanges
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 déclenchez
detectChanges()
. Ainsi, la détection des modifications s'exécutera pour le composant actuel et tous ses enfants. Angular contient des références à l'arborescence des composants racine dans leApplicationRef
et lorsqu'une opération asynchrone se produit, elle déclenche la détection de changement sur ce composant racine via une méthode wrappertick()
:view
voici la vue du composant racine. Il peut y avoir de nombreux composants racine comme je l'ai décrit dans la section Quelles sont les implications de l'amorçage de plusieurs composants .@milad a décrit les raisons pour lesquelles vous pourriez avoir besoin de déclencher manuellement la détection des modifications.
markForCheck
Comme je l'ai dit, ce type ne déclenche pas du tout la détection des changements. Il monte simplement du composant actuel au composant racine et met à jour leur état d'affichage en
ChecksEnabled
. Voici le code source:La détection de changement réelle pour le composant n'est pas planifiée, mais lorsqu'elle se produira dans le futur (dans le cadre du cycle CD actuel ou suivant), les vues du composant parent seront vérifiées même si elles avaient des détecteurs de changement détachés. Les détecteurs de changement peuvent être détachés en utilisant
cd.detach()
ou en spécifiant uneOnPush
stratégie de détection de changement. Tous les gestionnaires d'événements natifs marquent toutes les vues des composants parents pour vérification.Cette approche est souvent utilisée dans le
ngDoCheck
hook de cycle de vie. Pour en savoir plus, lisez cet article si vous pensezngDoCheck
que votre composant est en cours de vérification .Consultez également Tout ce que vous devez savoir sur la détection des changements dans Angular pour plus de détails.
la source
markForCheck
. Donc, si vous n'utilisez pas de tuyau asynchrone, c'est probablement ce que vous devriez utiliser. Cependant, gardez à l'esprit que la mise à jour du magasin doit se produire à la suite d'un événement asynchrone pour que la détection des modifications démarre. C'est presque toujours le cas. Mais il y a des exceptions blog.angularindepth.comasync pipe
car à l'intérieur de l'abonnement, nous avons généralement quelques choses à faire commecall setFromValues
do some comparison
.. et siasync
lui-même appellemarkForCheck
quel est le problème si nous l'appelons nous-mêmes? mais encore une fois, nous avons généralement 2-3 sélecteurs ou parfois plus pourngOnInit
obtenir des données différentes ... et nous les appelonsmarkForCheck
tous ... est-ce que c'est OK?cd.detectChanges()
exécutera la détection des modifications immédiatement à partir du composant actuel jusqu'à ses descendants.cd.markForCheck()
n'exécutera pas la détection des modifications, mais marquera ses ancêtres comme ayant besoin d'exécuter la détection des modifications. La prochaine fois que la détection des modifications s'exécutera n'importe où, elle s'exécutera également pour les composants qui ont été marqués.cd.markForCheck()
. Souvent, les modifications affectent plusieurs composants et la détection des modifications sera appelée quelque part. Vous dites essentiellement: assurons-nous simplement que ce composant est également mis à jour lorsque cela se produit. (La vue est immédiatement mise à jour dans chaque projet que j'ai écrit, mais pas dans chaque test unitaire).cd.detectChanges()
n'est pas en cours d' exécution , utilisezcd.markForCheck()
.detectChanges()
erreur dans ce cas. Cela signifie probablement que vous essayez de modifier l'état d'un composant ancêtre, ce qui va à l'encontre des hypothèses sur lesquelles la détection de changement d'Angular est conçue.detectChanges()
.markForCheck()
peut ne pas mettre à jour votre vue à temps. Le test unitaire, quelque chose affecte votre vue, par exemple, peut vous obliger à appeler manuellementfixture.detectChanges()
lorsque cela n'était pas nécessaire dans l'application elle-même.detectChanges()
car vous n'exécutez pas inutilement la détection des modifications sur les ancêtres du composant.la source