【问题标题】:Compare Observable's Previous Value With Next Value in Angular比较 Observable 的前一个值和 Angular 中的下一个值
【发布时间】:2017-09-13 17:20:46
【问题描述】:

我一直在开发一个允许几个不同组件在 Angular 中更新 BehaviorSubject 的应用程序。在每个组件中,我存储了前一个 BehaviorSubject 值的本地副本。为了知道组件是否生成了被推出的新值,我打算只使用 LoDash 的 _.isEqual() 函数比较两个对象。但是,我发现在进行比较之前,我的 Observable 本地副本已经更新。

Angular 是否会查找 = 语句并在 Observable next 函数之外创建到该组件属性的外部绑定?

鉴于下面的代码,我发现组件中的 this.QueryParams 属性已更新为函数中正在处理的当前值,即使我没有将新值分配给该属性,也会导致比较失败直到 if 语句被评估。

组件

export class LogsModalComponent implements OnInit {

    private QueryParams: LogsQueryParameters

    ngOnInit() {

        this._LogsService.QueryParameters$.subscribe(_QueryParams => {
            console.log(this.QueryParams);
            console.log(_QueryParams);

            if (!_.isEqual(this.QueryParams, _QueryParams) {
                this.QueryParams = _QueryParams;

                // Some code to process if the new value was different.
            }
        }
    }

    updateStartDate() {
        this.QueryParams.filterStartDate = _.isUndefined(this.FilterStartDate) ? NaN : new Date(this.FilterStartDate.nativeElement.value).getTime();
        this._LogsService.updateQueryParams(this.QueryParams);
}
}

服务

    LogsQueryParameters: BehaviorSubject<LogsQueryParameters> = new BehaviorSubject<LogsQueryParameters>({
            limit: 25,
            logLevels: "",
            logTypes: "",
            logUserIDs: "",
            filterStartDate: NaN,
            filterEndDate: NaN
        })
        LogsQueryParameters$ = this.LogsQueryParameters.asObservable();

    updateQueryParams(QueryParams) {
        this.LogsQueryParameters.next(QueryParams);
    }

【问题讨论】:

    标签: angular typescript rxjs lodash observable


    【解决方案1】:

    RxJS observables 有一个方法distinctUntilChanged(),它返回一个新的 observable,如果它与之前发出的值不同,它只会发出一个新值:

    this._LogsService.QueryParameters
        .distinctUntilChanged()
        .subscribe((_QueryParams) => this.QueryParams = _QueryParams);
    

    这适用于简单的比较。如果您仍然需要_.isEqual 函数,您可以将回调传递给distinctUntilChanged() 来执行比较:

    this._LogsService.QueryParameters
        .distinctUntilChanged((prev, curr) => _.isEqual(prev, curr))
        .subscribe((_QueryParams) => this.QueryParams = _QueryParams);
    

    请注意,您不会在回调中返回! ...,只要返回值为false(意味着被测值不等于),值通过。

    更新

    从您的最新编辑看来,您实际上是在传递完全相同的对象,并且只是改变了它的内容,正如@Brandon 在下面的评论中所建议的那样。您可以尝试在更新时创建一个新对象,通过Object.assign():

    updateStartDate() {
        this.QueryParams.filterStartDate = _.isUndefined(this.FilterStartDate)
            ? NaN 
            : new Date(this.FilterStartDate.nativeElement.value).getTime();
        this._LogsService.updateQueryParams(Object.assign({}, this.QueryParams));
    }
    

    对象实际上是通过引用传递的。

    请注意,new Date() 也会返回一个对象。该对象也通过引用传递和分配,只是这次Object.assign 不会帮助您,因为日期对象取决于原型链接(它不是 plain 对象)。

    【讨论】:

    • 感谢 Jeffrey,虽然我确信我将来会使用它,但它并不能真正解决问题。所有组件只有在它们有新值要发出时才会发出一个新值,但我正在尝试使用比较逻辑来让组件知道它们是否需要重新处理模型的某些部分。本质上,我试图防止循环。
    • 让我看看回调方法是否有效!感谢您的编辑。
    • 还是不行。不知何故,this.QueryParams 属性正在更新。但是它的设置等于任何东西的唯一位置是在比较函数中,在可观察订阅中。
    • 好的,this.QueryParams是怎么初始化的?
    • 是的。如果您以函数式风格编写代码,RxJs 效果最好。更具体地说,如果您只通过可观察对象传递 不可变 对象,一切都会更好。
    【解决方案2】:

    对于那些想要将之前的值与 Observable(或 BehaviourSubject)的当前值进行比较的人,只需使用 pairwise 运算符即可。例如:

    ngOnInit() {
        this._logsService.yourObservable$.pipe(pairwise()).subscribe(([previous, current]) => {
            if (previous !== current) {
                // Some code to process if the new value was different.
            }
        }
    }
    

    【讨论】:

    • 注意如果你是成对使用,只有在超过一个值时才会执行,所以一般需要添加startWith $observable.pipe(startWith(actual_value),pairwise())..)
    猜你喜欢
    • 2019-02-22
    • 2017-01-08
    • 1970-01-01
    • 1970-01-01
    • 2017-11-25
    • 2022-09-27
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    相关资源
    最近更新 更多