J'ai un flux d'objets et je dois comparer si l'objet actuel n'est pas le même que le précédent et dans ce cas émettre une nouvelle valeur. J'ai trouvé que l'opérateur distinctUntilChanged devrait faire exactement ce que je veux, mais pour une raison quelconque, il n'émet jamais de valeur sauf la première. Si je supprime les valeurs distinctUntilChanged, elles sont émises normalement.
Mon code:
export class SettingsPage {
static get parameters() {
return [[NavController], [UserProvider]];
}
constructor(nav, user) {
this.nav = nav;
this._user = user;
this.typeChangeStream = new Subject();
this.notifications = {};
}
ngOnInit() {
this.typeChangeStream
.map(x => {console.log('value on way to distinct', x); return x;})
.distinctUntilChanged(x => JSON.stringify(x))
.subscribe(settings => {
console.log('typeChangeStream', settings);
this._user.setNotificationSettings(settings);
});
}
toggleType() {
this.typeChangeStream.next({
"sound": true,
"vibrate": false,
"badge": false,
"types": {
"newDeals": true,
"nearDeals": true,
"tematicDeals": false,
"infoWarnings": false,
"expireDeals": true
}
});
}
emitDifferent() {
this.typeChangeStream.next({
"sound": false,
"vibrate": false,
"badge": false,
"types": {
"newDeals": false,
"nearDeals": false,
"tematicDeals": false,
"infoWarnings": false,
"expireDeals": false
}
});
}
}
J'ai eu le même problème et l'ai résolu en utilisant JSON.stringify pour comparer les objets:
.distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
Code sale mais fonctionnel.
Je trouve enfin où est le problème. Le problème était dans la version de RxJS, dans V4 et plus tôt, l'ordre des paramètres est différent de V5.
RxJS 4:
distinctUntilChanged = fonction (keyFn, comparateur)
RxJS 5:
distinctUntilChanged = fonction (comparateur, keyFn)
Dans tous les documents d'aujourd'hui, vous pouvez trouver l'ordre des paramètres V4, méfiez-vous!
Quand vous avez de toute façon lodash dans votre application, vous pouvez simplement utiliser la fonction isEqual()
de lodash, qui fait une comparaison approfondie et correspond parfaitement à la signature de distinctUntilChanged()
:
.distinctUntilChanged(isEqual),
Ou si vous avez _
disponible (ce qui n'est plus recommandé de nos jours):
.distinctUntilChanged(_.isEqual),
La solution de Mehdi est rapide mais ne fonctionnera pas si la commande n'est pas maintenue. Utilisation de l'une des bibliothèques deep-equal ou fast-deep-equal :
.distinctUntilChanged((a, b) => deepEqual(a, b))
De RxJS v6 +, il y a distinctUntilKeyChanged
https://www.learnrxjs.io/operators/filtering/distinctuntilkeychanged.html
const source$ = from([
{ name: 'Brian' },
{ name: 'Joe' },
{ name: 'Joe' },
{ name: 'Sue' }
]);
source$
// custom compare based on name property
.pipe(distinctUntilKeyChanged('name'))
// output: { name: 'Brian }, { name: 'Joe' }, { name: 'Sue' }
.subscribe(console.log);
Si vous modifiez la valeur de manière mutuelle, aucune des autres réponses ne fonctionne. Si vous devez travailler avec des structures de données mutables, vous pouvez utiliser distinctUntilChangedImmutable
, qui copie en profondeur la précédente et si aucune fonction de comparaison n'est transmise, affirmera que les valeurs précédentes et actuelles profondes sont égales (et non === assertion).