ChangeDetectionStrategy.OnPush et Observables.abonnez-vous dans Angulaire 2
Je suis d'essayer d'envelopper ma tête autour des meilleures pratiques lors de l'utilisation des Observables aux côtés de ChangeDetectionStrategy.OnPush
.
L'exemple montre le scénario commun de vouloir montrer une sorte de message de chargement (ou une simple toupie d'animation peut-être):
@Component({
selector: 'my-app',
template: `Are we loading?: {{loadingMessage}}`,
//Obviously "Default" will notice the change in `loadingMessage`...
//changeDetection: ChangeDetectionStrategy.Default
//But what is best practice when using OnPush?
changeDetection: ChangeDetectionStrategy.OnPush
})
export class App implements OnInit {
private loadingMessage = "Wait for it...";
constructor() {
}
ngOnInit() {
//Pretend we're loading data from a service.
//This component is only interested in the call's success
Observable.of(true)
.delay(2000)
.subscribe(success => {
if(success){
console.log('Pretend loading: success!');
//OnPush won't detect this change
this.loadingMessage = 'Success!';
}
});
}
}
J'ai plus ou moins de comprendre l'exigence de l'immutabilité avec OnPush
et, pour moi, au moins, elle n'a de sens lorsque l'on parle de réel modèle de données (probablement eu lieu dans une sorte de magasin).
Donc, j'ai deux questions:
- Pourquoi ne pas l'affectation de la nouvelle chaîne de valeur
'Success!'
déclencher le changement de détecteur? Aussi loin que l'immuabilité est en cause, valeur a changé, non? - Comment doit-léger composant interne de l'état (c'est à dire.
loadingMessage
) être mis en œuvre lors de l'utilisation deChangeDetectionStrategy.OnPush
? S'il y a plusieurs bonnes pratiques, merci de me pointer dans la bonne direction.
Vous devez vous connecter pour publier un commentaire.
Bonne question. J'ai deux citations de Savkin sur
onPush
(depuis l'angle.io docs ne semble pas avoir des infos sur ce sujet encore):La seconde citation semble plus complète. (Dommage qu'il a été enterré dans un commentaire!)
OnPush
immutabilité est en référence à des propriétés d'entrée, pas normal propriétés d'une instance. SiloadingMessage
ont une entrée de la propriété et de la valeur a changé, la détection de changement à l'exécution sur le composant. (Voir @Vlado réponse à Plunker.)Voici ce que je sais:
OnPush
composant (c'est à dire, la vue de mise à jour). Dans votre cas particulier, j'ai été surpris de voir que le point de vue n'a pas de mise à jour. Voici deux devine pourquoi pas:delay()
rend Angulaire de le regarder plus comme unsetTimeout()
plutôt que d'un changement observable.setTimeout
s n'entraînent pas de changement de détection d'exécution sur unOnPush
composant. Dans votre exemple, le Changement de Détecteur a terminé son travail de 2 secondes avant que la valeur deloadingMessage
est changé.Observable
. I. e., peut-être qu'il est plus que juste "une observable feux"... peut-être qu'il a à être un lié observables que les incendies. Dans ce cas, la création deloadingMessage
(ou même plus génériquestate
de propriété) d'unObservable
lui-même vous permettra de lier votre modèle de sa valeur (ou de plusieurs async valeurs), voir cet exemple plnkr.Mise à jour 2016-04-28: il semble que la liaison doit inclure
| async
, comme indiqué dans le plnkr, et dans cette plnkr.ChangeDetectorRef
dans notre composant et d'appel de la méthodemarkForCheck()
à cause de la détection de changement à exécuter sur leOnPush
composant et tous ancêtre des composants jusqu'à la racine de composant. Si seulement l'état d'affichage est modifié (c'est à dire, de l'état de ce qui est local pour le composant et peut-être ses descendants),detectChanges()
peut être utilisé à la place, qui ne marque pas tous les ancêtre des composants pour la détection de changement. PlunkermarkForCheck()
(je suis à la limite si c'est un peu hacky ou acceptable). Ou la création d'unloadingMessage
oustate
valeur comme uneObservable
lui-même, de cette façon, il peut représenter plusieurs membres de ce plnkr. Je pense que je vais l'ajouter à votre réponse et de l'accepter tel qu'il apparaît à couvrir toutes les bases.OnPush
a unnumberOfTicks
propriété qui est mise à jour dans unsetTimeout()
de rappel, etmarkForCheck()
est appelé à assurer l'affichage des mises à jour.ChangeDetectorRef.markForCheck()
Autant que je sache,
OnPush
est utilisé lors d'un travail directement observables:Observable
n'est pas faite dansngOnInit
, mais plutôt au sein d'un gestionnaire de soumission de formulaire. Sens de la liaison de modèle doit être{{ loadingMessage && loadingMessage | async }}
.state
, le chargement est juste un de plusieurs états. Je suppose questate
pourrait être un autre interneObservable
, que par cette plnkr. Plusieursstate
valeurs pourrait être poussé au fil du temps.valueChanges
de la propriété). Vous pouvez voulez regarder en trop...Avec cette
ChangeDetectionStrategy.OnPush
vous dites votre composant pour n'écouter que pour les modifications sur les propriétés d'entrée.J'ai ajouté chargement du composant à votre exemple, juste pour vous montrer comment ça fonctionne:
http://plnkr.co/edit/k5tkmcLlzkwz4t5ifqFD?p=preview
loadingMessage
n'est pas rendu àtest
, comme nous l'avons défini la valeur detest
dans le derniersetTimeout
. Quelqu'un pourrait-il m'aider à m'expliquer cela?