Search code examples
javascriptstreamrxjsrxjs5frp

RxJS: correct patterns for identifying stream source in combined stream?


I am looking for some best-practice suggestions on how to identify which stream is coming in to a merge or combineLatest function in such a way that only the new stream is operated on.

In the context of a TODO app, I have incoming add and remove streams, and I want to combine them so that my list editing can occur within a single stream in a stateless manner. The output is a list that has integrated both add(concat) and remove(filter) events, otherwise you seem to end up with other streams that include all the add or remove events and thus grow infinitely.

Problems encountered include:

  • using merge does not indicate which stream is incoming;
  • using combineLatest does not indicate which stream has triggered the subscribed stream, so you can't only perform the operations relevant to that stream.
  • using withLatestFrom results in a new list that does not update the withLatestFrom input source, so unless the next stream also interested in this list subscribes to that list, the list will get out of sync (or you have every new list based on the one before it, which causes needless re-stepping through every transformation for those that happened prior to it...).

Currently found approaches that somehow seem sub-optimal include:

  • The Cycle JS TODO app explicitly assigns type properties directly to the created objects of the earlier streams for identification, which I would have thought should be avoided in favor of using RxJS methods that directly identify where the streams come from?
  • taking the suggestion from http://www.jisaacks.com/manipulating-rxjs-streams/ and splitting the output of addition streams and removal streams to [null, {addItem}] and [removeItem, {null}], such that when using merge for both add and remove events, I could still identify the incoming stream which was being updated, so that I could perform both addition and removal in a single stream (but then I want to add toggle events, etc, but this doesn't seem right either since I'm needing to create stream outputs that are aware of all the other potential streams (ending up with [null, null, myOutput, null, null etc].

Any best practice suggestions are very welcome.


Solution

  • There is no Rxjs method which allows to identify where a stream comes from. Streams do not carry a name on them. If you want one, you need to put it yourself. So find another way to put a name on them if you like none of those two ways. If your question is what is the best practice to put an identifier on an object, then the answer is put an identifier on the damn object.

    The way I personally favour is through a curried function :

    function label(identifier){return function (x){var obj={};obj[identifier]=x;return obj;};}
    

    which I use as follows:

    source1.map(label('remove')).merge(source2.map(label('add')))
    

    but really, do as you please, how you do this is a rather minor issue, in my opinion.