Ответ 1
У меня была та же проблема и исправлена с помощью JSON.stringify для сравнения объектов:
.distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
Грязный, но рабочий код.
У меня есть поток объектов, и мне нужно сравнить, если текущий объект не такой же, как предыдущий, и в этом случае испускает новое значение. Я обнаружил, что оператор differUntilChanged должен делать именно то, что я хочу, но по какой-то причине он никогда не испускает значение, кроме первого. Если я удаляю значение differUntilChanged, выдается нормально.
Мой код:
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
}
});
}
}
У меня была та же проблема и исправлена с помощью JSON.stringify для сравнения объектов:
.distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
Грязный, но рабочий код.
Наконец-то выясню, где проблема. Проблема была в версии RxJS, в V4 и более ранних - порядок, отличный от V5.
RxJS 4:
distinctUntilChanged = function (keyFn, comparer)
RxJS 5:
distinctUntilChanged = function (comparer, keyFn)
В каждом документе сегодня вы можете найти порядок параметров V4, остерегайтесь этого!
В любом случае, если в вашем приложении есть lodash, вы можете просто использовать функцию lodash isEqual()
, которая выполняет глубокое сравнение и идеально соответствует сигнатуре isEqual()
distinctUntilChanged()
:
.distinctUntilChanged(isEqual),
Или, если у вас есть _
наличии (что больше не рекомендуется в наши дни):
.distinctUntilChanged(_.isEqual),
Решение Mehdi хоть и быстрое, но не сработает, если порядок не будет соблюден. Использование одной из библиотек с глубоким или быстрым глубоким равенством:
.distinctUntilChanged((a, b) => deepEqual(a, b))
Если вы изменяете значение изменчиво, ни один из других ответов не сработает. Если вам нужно работать с изменчивыми структурами данных, вы можете использовать distinctUntilChangedImmutable
, которая копирует глубокое предыдущее значение, и если функция сравнения не передается, будет утверждать, что предыдущее и текущее значения глубоко равны каждому другое (не === утверждение).
От RxJS v6+ есть отличныйUntilKeyChanged
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);