我有对象流,我需要比较当前对象是否与之前的对象不同,在这种情况下发出新值。我发现distinctUntilChanged操作符应该完全符合我的要求,但由于某种原因,除了第一个之外它永远不会发出值。如果我删除distinctUntilChanged值正常发生。
我的代码:
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
}
});
}
}
答案 0 :(得分:19)
我终于找出问题所在。问题出在RxJS的版本中,在V4中,之前的参数顺序与V5不同。
RxJS 4:
distinctUntilChanged = function(keyFn,comparer)
RxJS 5:
distinctUntilChanged = function(comparer,keyFn)
在今天的每个文档中,您都可以找到V4参数顺序,请注意!
答案 1 :(得分:19)
我遇到了同样的问题,并使用JSON.stringify来比较对象:
.distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
脏但工作的代码。
答案 2 :(得分:2)
无论如何,只要在应用程序中包含lodash,就可以简单地使用lodash的isEqual()
函数,该函数进行了深入的比较,并且与distinctUntilChanged()
的签名完全匹配:
.distinctUntilChanged(isEqual),
或者如果您有_
可用(现在不建议这样做):
.distinctUntilChanged(_.isEqual),
答案 3 :(得分:1)
您还可以包装原始的distinctUntilChanged
函数。
function distinctUntilChangedObj<T>() {
return distinctUntilChanged<T>((a, b) => JSON.stringify(a) === JSON.stringify(b));
}
这使您可以像原始版本一样使用它。
$myObservable.pipe(
distinctUntilChangedObj()
)
答案 4 :(得分:1)
如果可观察对象实际上发出相同对象的修改版本,则建议深度比较的答案都失败了,因为传递给比较的“最后”值将与当前,每次。
我们使用 BehaviorSubject 来实现这一点,碰巧每次都将相同的对象传递给 .next()。
在这种情况下,无论您使用什么比较函数,都无法使用默认的 distinctUntilChanged 解决方案。
答案 5 :(得分:0)
Mehdi的解决方案虽然速度很快,但是如果不维护订单将无法使用。使用deep-equal或fast-deep-equal库之一:
.distinctUntilChanged((a, b) => deepEqual(a, b))
答案 6 :(得分:0)
如果您可变地更改该值,则其他答案均无效。如果需要使用可变数据结构,则可以使用 distinctUntilChangedImmutable
,它会深度复制前一个值,并且如果未传递任何比较函数,则会断言前一个值和当前值彼此相等(不是===断言)。
答案 7 :(得分:0)
来自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);
答案 8 :(得分:0)
您也可以制作自己的过滤器:
function compareObjects(a: any, b: any): boolean {
return JSON.stringify(a) === JSON.stringify(b);
}
export function distinctUntilChangedObject() {
return function<T>(source: Observable<T>): Observable<T> {
return new Observable(subscriber => {
let prev: any;
let first = true;
source.subscribe({
next(value) {
if (first) {
prev = value;
subscriber.next(value);
first = false;
} else if (!compareObjects(prev, value)) {
prev = value;
subscriber.next(value);
}
},
error(error) {
subscriber.error(error);
},
complete() {
subscriber.complete();
}
});
});
};
}