RxJS distinctUntilChanged - 对象比较

Dan*_*chý 18 reactive-programming rxjs angular

我有对象流,我需要比较当前对象是否与以前相同,在这种情况下发出新值.我发现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
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

Meh*_*oha 23

我遇到了同样的问题,并使用JSON.stringify来比较对象:

.distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))

肮脏但工作的代码.

  • 我不了解您的情况,JSON.stringify只会将对象转换为字符串。即使您没有相同的属性顺序,它也不起作用! (2认同)

Dan*_*chý 21

我终于找出问题所在.问题出在RxJS的版本中,在V4中,之前的参数顺序与V5不同.

RxJS 4:

distinctUntilChanged = function(keyFn,comparer)

RxJS 5:

distinctUntilChanged = function(comparer,keyFn)

在今天的每个文档中,您都可以找到V4参数命令,请注意!


Whi*_*her 8

从 RxJS v6+ 开始,有 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);
Run Code Online (Sandbox Code Playgroud)


Ben*_*ing 8

您也可以包装原始distinctUntilChanged函数。

function distinctUntilChangedObj<T>() {
  return distinctUntilChanged<T>((a, b) => JSON.stringify(a) === JSON.stringify(b));
}
Run Code Online (Sandbox Code Playgroud)

这让您可以像原始版本一样使用它。

$myObservable.pipe(
  distinctUntilChangedObj()
)
Run Code Online (Sandbox Code Playgroud)


hoe*_*eni 7

无论如何,当您的应用程序中有lodash时,您可以简单地使用lodash的isEqual()函数,该函数进行了深入的比较,并且与的签名完全匹配distinctUntilChanged()

.distinctUntilChanged(isEqual),
Run Code Online (Sandbox Code Playgroud)

或者,如果您有_空位(最近不建议这样做):

.distinctUntilChanged(_.isEqual),
Run Code Online (Sandbox Code Playgroud)

  • @Bobby_Cheh 当您导入`_`符号时,这包括lodash的*所有*功能,无论您是否使用它。这不能在以后减少到真正需要的,以减少构建过程中生成的包大小(这称为“Tree Shaking”,因为所有未连接的东西都会掉落:-))。当您只需要所需的单个函数时,只有这些函数会绑定到您的最终程序包:例如“import {isEqual} from 'lodash'”。现在它是可摇树的,因此您未使用的所有 lodash 功能(可能是 lodash 的大部分;-) )都不会包含在内。 (4认同)

Wil*_*mer 5

迈赫迪的解决方案虽然速度很快,但如果不维护订单,就无法工作。使用deep-equalfast-deep-equal库之一:

.distinctUntilChanged((a, b) => deepEqual(a, b))
Run Code Online (Sandbox Code Playgroud)