简体   繁体   English

如何比较可观察对象:NGRX和使用可观察对象的可观察对象进行有效的Angular 4渲染

[英]How to compare Observables: NGRX and Working with Observables of Observables for efficient Angular 4 Rendering

OVERVIEW 总览

Were following the container -> component pattern and using ngrx for centralizing our applications state. 遵循容器->组件模式,并使用ngrx集中我们的应用程序状态。

The app structure is something such as: 应用程序的结构如下:

Container
   Child_Comp_1
      Child_Comp_2
         Child_Comp_3

Originally, there was a single observable of the data subscribed to at the Container, then the relative data passed as inputs to child components. 最初,只有一个可观察的数据可以在Container上订阅,然后将相对数据作为输入传递给子组件。 such as

Observable<
 {
   data,
   collection: []
 }> 

However, any update triggered the ngrx selector and caused a AngularJS re-rendering down the chain of components. 但是,任何更新都会触发ngrx选择器,并导致AngularJS重新渲染组件链。

We moved to serving up observables of observables, 我们开始提供可观察物,

Observable< 
 {
  data: Observable<data>
  collection: Observable<Observable<Item>[]>
 }>

We can now use RxJs functions such as DistinctUntilChanged(predicate) to specify when a subscription in a component is actually triggered. 现在,我们可以使用诸如DistinctUntilChanged(predicate)之类的RxJs函数来指定何时实际触发组件中的订阅。

And use ChangeDetection.markForCheck() which will limit where the re-rendering occurs 并使用ChangeDetection.markForCheck()它将限制重新渲染的位置

PROBLEM & QUESTION 问题与问题

There are two problems 有两个问题

  1. Taking our array of Observable - Whats the best way to compare the values of two Observables to see if any changed 以我们的Observable数组-比较两个Observable的值以查看是否有任何更改的最佳方法是什么

example: 例:
collection.distinctUntilChanged((a, b) => ?? compare values of ab ??)

  1. Working with Observables of Observables so that different child components can define the criteria of when a subscription is triggered makes other areas more difficult. 使用Observables的Observables,以便不同的子组件可以定义何时触发订阅的标准,这会使其他区域更加困难。 Is there a better approach? 有没有更好的方法?

Example: 例:

Child Comp 儿童比赛

  collection
   .distinctUntilChanged((a, b) => a.length === b.length)
   .subscribe(items => ....)  // only fired if length changed

The way I would do this is to just send a value through and derive observables from it rather than sending observables of observables. 我这样做的方法是只发送一个值并从中获取可观察值,而不是发送可观察值的可观察值。

private subj: Subject<{data:any, collection: any[]}> = new Subject<{data:any, collection: any[]}>();
src$: Observable<{data:any, collection: any[]}> = this.subj.distinctUntilChanged();
data$: Observable<any> = this.src$.pluck('data').distinctUntilChanged();
collection$: Observable<any[]> = this.src$.pluck('collection').distinctUntilChanged();

this.src$.subscribe(v => console.log(v));
this.data$.subscribe(v => console.log(v));
this.collection$.subscribe(v => console.log(v));

the default behavior of distinctUntilChanged is an object reference (or primitive) comparison. uniqueUntilChanged的默认行为是对象引用(或原始)比较。 So the key is to enforce object immutability and only alter objects that need updates and to rereference them when you do. 因此,关键是强制实现对象不变性,并且仅更改需要更新的对象,并在需要时重新引用它们。

const obj = { data: {}, collection: []; };
this.subj.next(obj); // all subscribers trigger
const dataUpdate = Object.assign({}, obj, {data: { prop1:'new Val' }}); // change only the data property, collection untouched
this.subj.next(dataUpdate); //src and data trigger
const collUpdate = Object.assign({}, dataUpdate, { collection: [1] }); // change only collection property, data untouched
this.subj.next(collUpdate); //src and coll fire
const collUpdate2 = Object.assign({}, collUpdate, { collection: collUpdate.collection.concat([2]) }); // add to existing collection
 this.subj.next(collUpdate2); //src and coll fire
const collUpdate3 = Object.assign({}, collUpdate2, { collection: collUpdate2.collection.splice(0,1) }); //reomve from existing collection
 this.subj.next(collUpdate3); //src and coll fire

this is the general pattern, take your last value, and your update, and apply the update in such a way that it only updates the pieces that should be updated, including all of it's ancestors. 这是常规模式,采用您的最后一个值以及您的更新,并以仅更新应更新的片段(包括其所有祖先)的方式应用更新。 This is what ngrx really does under the hood, it uses the scan operator, which takes your accumulated vallue (last value) and your new action (your update) and applies the change in such a way that only pieces that need updating get updated (the reducer). 这就是ngrx真正在做的事情,它使用扫描运算符,该运算符将获取您累积的价值(最后一个值)和新操作(您的更新),并以仅需更新的部分进行更新的方式应用更改(减速器)。 ngrx's "select" function also takes care of all the distinctUntilChanged() stuff so you don't need to worry about it. ngrx的“选择”功能还可以处理所有与众不同的UntilChanged()内容,因此您无需担心。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM