RxJS Observable:当对象的特定部分发生变化时发出

RxJS Observable:当对象的特定部分发生变化时发出

问题描述:

我有一个拥有子对象和数组等的复杂对象。RxJS Observable:当对象的特定部分发生变化时发出

我可以很容易地从这个对象创建一个Subject/BehaviourSubject或Observable,这样我就可以“向下”(发出)新的状态给订阅者。

[例如:let appEnv$ = new Rx.BehaviorSubject<IWebSocketAppEnv>(appEnv);]

不过,我不希望我的所有用户将每次通知的对象更改。例如,对于我的一位订阅者,我只想在该对象的数组元素发生更改时收到通知。

其实我想要的是REDX已经在做的事情。在REDX中,我可以订阅商店,但只选择一个子元素。

我想为我的后端websocket服务器应用程序实现相同的基础结构。

如何用RxJS实现这一目标?

+0

我想你不希望在你的应用程序中使用终极版? –

+0

是的,希望。我已经在客户端运行了REDX(Angular),并且在服务器端我只是希望有一些Rxjs主题来处理它,如果可能的话。 –

+0

像ngrx ['select'](https://github.com/ngrx/core/blob/v1.2.0/src/operator/select.ts)操作符听起来适合您的用例。 – cartant

使用distinctUntilChanged运营商。 (docs)

假设该对象的结构是:

{ 
    articleId: 0, 
    comments: [ 'lorem', 'ipsum' ] 
} 

我们希望成为酷派为火力的家伙,所以当更新的对象有不同的阵列,我们将更新实时评论。

我使用RxJS5作为观测值,lodash比较数组,因为操作符的默认行为不会以我们希望比较它们的方式进行比较。

// Our BehaviorSubject which emits new object. 
// For those who don't know: it'll emit the latest emitted value when subscribing to it. 
const object$ = new Rx.BehaviorSubject({ 
    articleId: 0, 
    comments: [], 
}); 

// If you want specific parts of your application 
// to react only when a specific part of the object has changed, you 
// have to create another observable using 'map' and 
// 'distinctUntilChanged' operator and subscribe to it. 
const comments$ = object$ 
    .map(object => object.comments) // we want to emit comments only 
    .distinctUntilChanged((a, b) => _.isEqual(a, b)); // emit only when currently emitted value is different than previous one. 

comments$.subscribe(v => console.log(v)); // log fresh comments 

object$.next({ 
    articleId: 1, 
    comments: [], 
}); 

object$.next({ 
    articleId: 1, 
    comments: ['lorem', 'ipsum'], 
}); 

object$.next({ 
    articleId: 2, 
    comments: ['lorem', 'ipsum'], 
}); 

object$.next({ 
    articleId: 2, 
    comments: ['lorem', 'ipsum', 'dolor', 'sit', 'amet'], 
}); 

效果:

[] 
["lorem", "ipsum"] 
["lorem", "ipsum", "dolor", "sit", "amet"] 

效果,而distinctUntilChanged操作:

[] 
[] 
["lorem", "ipsum"] 
["lorem", "ipsum"] 
["lorem", "ipsum", "dolor", "sit", "amet"] 

JSFiddle

+0

嗨,@ mustafa-ekim。如果此答案解决了您的问题,请考虑将其标记为已接受,方法是单击投票数下方的图标。 –

+0

我认为_.isEqual(a,b)应该是!_ isEqual(a,b),对吗? –

+0

根据文档,它必须返回false才能发出新的值。在这种情况下'_.isEqual(a,b)'是一个有效的比较。 –

我们可以通过根据条件部分订阅源observable(在您的情况下为复杂对象)来解决它。

Rxjs takeWhile有助于做到这一点。 只有在满足特定条件时才能进行订阅,然后处理发出的输出。

https://www.learnrxjs.io/operators/filtering/takewhile.html

+0

'takeWhile'将完成你的流,所以它不能真正用于跟踪原始$ env对象的子树的所有更改。 –