What is the purpose of next('r') in the context of an RxJS Subject - reactjs

I'm still fairly new to the RxJS world (please pardon my semantics), but I've seen a few examples of code that creates a Subject to do some work, and then calls next(0), or next('r') on the subscription. It appears to re-run the stream, or rather fetch the next value from the stream.
However, when I tried using this to call an API for some data, it completely skips over the work it's supposed to do as defined in the stream (assuming it would "run" the stream again and get new data from the server), and instead my subscriber gets the 'r' or zero value back when I try to call next like that.
I get that making the subscription "starts execution of the stream", so to speak, but if I want to "re-run" it, I have to unsubscribe, and resubscribe each time.
Is it a convention of some kind to call next with a seemingly redundant value? Am I just using it in the wrong way, or is there a good use-case for calling next like that? I'm sure there's something fundamental that I'm missing, or my understanding of how this works is very wrong.

It's a good question, I definitely recommend you to read about hot and cold Observables.
cold Observables execute each time someone subscribes to it.
const a$ = of(5).pipe(tap(console.log))
a$.subscribe(); // the 'tap' will be executed here
a$.subscribe(); // and here, again.
hot Observables do not care about subscriptions in terms of execution:
const a$ = of(5).pipe(
tap(console.log),
shareReplay(1)
);
a$.subscribe(); // the 'tap' will be executed here
a$.subscribe(); // but not here! console.logs only once
In your example you are using Subject that represents cold Observable.
You can try to use BehaviorSubject or ReplaySubject - both of them are hot but be aware that they behave differently.
IN you example you can modify your Subject like the following:
const mySubject = new Subject();
const myStream$ = mySubject.pipe(
shareReplay(1)
);
myStream$.subscribe(x => console.log(x))
mySubject.next(1);
mySubject.next(2);
mySubject.next(3);

Related

Understanding react function notation

Learning react here. Can someone walk me through how to interpret the function below:
const onElementsRemove = (elementsToRemove) => setElements((els) => removeElements(elementsToRemove, els));
As far as I understand it, this is the same as calling:
onElementsRemove(setElements(elementsToRemove(els))?
Is that correct? Is there a benefit to the first notation? Perhaps I am biased coming from the python side of the world but the second one feels more compact? Can someone help me undrstand the reasoning? Thanks!
No, those are not the same. Let's start with the inner part, which needs to be the way it is:
setElements((els) => removeElements(elementsToRemove, els))
When setting state in react, there are two options. You can either directly pass in what you want the new state to be, or you can pass in a function. If you pass in a function, then react will look up what the latest value of the state is, and call your function. Then you return what the new state will be.
So the purpose of doing it this way is to find out what the latest value in the state is. There isn't another way to do this.
Next, the outer part, which has more flexibility:
const onElementsRemove = (elementsToRemove) => /* the stuff we looked at earlier */
This is defining a function called onElementsRemove. From the name, i assume that this is going to be called at some arbitrary point of time in the future. So it's just defining the functionality, and later on you can call it, once you know which elements you want to remove. It will then turn around and set the state. For example, you would do:
onElementsRemove([1, 2, 3]); // i don't actually know what will be in the array
Maybe having this outer function is useful, maybe not. If you're having to do this fairly often it could make sense. In other cases, maybe you could directly call setElements, as in:
setElements((els) => removeElements([1, 2, 3], els));

RxJS DOM pause observable while another "is dragging"?

UPDATE
I've tried to make a standalone version here: https://codepen.io/neezer/pen/pPRJar
It doesn't work quite like my local copy, but I'm hoping it similar enough that you can see where I'm trying to go.
I'm not getting quite the same behavior as well because I changed the listener target to document, which seemed to help some.
Also, I'm using RxJS v5 and the latest version of React.
Still getting the hang of RxJS...
I have two Observables: one subscribed to mouseover x coordinates on a table to show a resize column, and the other to allow the user to drag on that column.
Roughly speaking, the first one looks like this (all of the below defined in a componentDidUpdate lifecycle method in a React component):
Rx.DOM.mouseover(tableEl)
.map(/* some complicated x coordinate checking */)
.distinctUntilChanged()
.subscribe(/* setState call */)
That works great, and gives me this:
So now I want to provide the actual "drag" behavior, and I tried setting up a new Observable like so
// `resizerEl` is the black element that appears on hover
// from the previous observable; it's just a div that gets
// repositioned and conditionally created
Rx.DOM.mousedown(resizerEl)
.flatMap(md => {
md.preventDefault()
return Rx.DOM.mousemove(tableEl)
.map(mm => mm.x - md.x)
.takeUntil(Rx.DOM.mouseup(document))
})
.subscribe(/* do column resizing stuff */)
There are three problems with that:
Once I've done my first "drag", I can't do any more. My understanding is that takeUntil completes the Observable, and I'm not sure how I can "restart" it.
The mousemove from the first observable is still active while I'm dragging, so my black div will disappear once my x position changes enough to trigger that behavior.
The binding on the second Observable doesn't always seem to trigger (it's unreliable). I think there might be a race condition or something happening here because sometimes I'll refresh the page and I'll get the drag once (from #1), and other times I won't get it at all.
Note at first after a clean refresh I can't drag the handle (#3), then I refresh, and I can't drag the handle past the bounds setup from the first Observable--and the black resizer bar disappears and reappears as my mouse's x coordinate enters and leaves that envelope (#2).
I've been head-banging on this for quite some time now and would really appreciate any insight as to what I'm doing wrong here. In short, I want
the first Observable to "pause" when I'm dragging, then resume when I'm done dragging
the second Observable to not "complete" (or "restart") once a drag is done
the second Observable to reliably work
As I mentioned earlier, I currently have this logic setup in a React component's componentDidUpdate lifecycle method, the shape of which looks roughly like this:
componentWillUpdate() {
// bail if we don't have the ref to our table
if (!tableEl) {
return;
}
// try not to have a new Observable defined on each component update
if (!this.resizerDrag$ && this.resizer) {
this.resizerDrag$ = // second Observable from above
}
// try not to have a new Observable defined on each component update
if (!this.resizerPos$) {
this.resizerPos$ = // first Observable from above
}
}
I've played around with this a bit now, I don't think this answer will be complete, but I'd like to share my insights. Hopefully a more advanced RxJS mind will chime in, and we can all work together to figure it out :).
I recreated a "lite-er" version of this in CodePen, using some light jQuery manipulation as opposed to React. Here's what I have so far:
"the first Observable to "pause" when I'm dragging, then resume when I'm done dragging"
Solving the first point helps with the other two. Based on what I had to do to get my resizerEl, I get the feeling it is rendered in the render method of the component based on something in this.state. If this is true, that means that when the first observable still has the ability to create and destroy resizerEl even while the second observable is listening. This means that resizerEl will no longer be able to generate any events, even though the observable doesn't complete until you've moused up.
In my case, I noticed that if you moved the mouse fast enough to go outside of width of what you were trying to drag, it would eliminate resizerEl, which is of what we want, but not while we're trying to drag something!
My solution: I introduced another variable to the "state" of the "component". This would set to true when we moused down on resizerEl, and then false when we moused up again.
Then we use switchMap.
Rx.DOM.mousemove(tableEl)
.switchMap(function(event) {
return this.state.mouseIsDown ? Rx.Observable.never() : Rx.Observable.of(event);
})
.map(...
There's probably a better way to do it rather than just sticking event back in an Observable, but this was the last part of it I worked on and my brain is kind of fried hehe. The key here is switching to Observable.never while the mouse is down, that way we don't go any further down the operator chain.
Actually, one nice thing is that this may not even need to be put in this.state, since that would cause a re-render. You can probably just use an instance variable, since the variable is only essential to the Observables functionality, and not any rendering. So, using this.mouseIsDown would be just as good.
How do we handle the mouse being down or up?
Part 1:
...
Rx.DOM.mousedown(resizerEl)
.do(() => this.mouseIsDown = true)
Better to abstract this to a function of course, but this is the gist of what it does.
Part 2:
...
return Rx.DOM.mousemove(tableEl)
.map(mm => mm.x - md.x)
.takeUntil(Rx.DOM.mouseup(document))
.doOnCompleted(() => this.mouseIsDown = false)
Here we take advantage of doOnComplete to perform this side-effect once the observable has completed, which in this case, would be on mouseup.
"the second Observable to not "complete" (or "restart") once a drag is done"
Now here's the tricky one, I never ran into this problem. You see, every time Rx.DOM.mousedown(resizerEl) emits an event, inside of flatMap, a new Observable is created each time with return Rx.DOM.mousemove(tableEl).... I used RxJS 4.1 when making this, so it's possible that there could be behavioral differences, but I found that just because the inner observable completed didn't mean the outer one would complete as well.
So what could be happening? Well, I'm thinking that since you're using React, that resizerEl is being created/destroyed respectively when the component is rendering. I haven't seen the rest of your code of course, but please correct me if I'm wrong about this assumption.
This wasn't a problem for me because, for the sake of simplicity, I simply re-used the same element as a dragger, only hiding it when I wasn't hovering over a draggable element.
So the important question is: how is resizerEl being defined and used in your component? I'm assuming the actual reference to it is made using, well, a ref. But if it that DOM element is ever destroyed or recreated, then the Rx.Dom binding needs to be repeated all over again.
I see you're doing this with componentDidUpdate. However, the Rx.Dom.mousedown event may still be bound to an old copy of the ref to resizerEl. Even if the component destroys the resizer in the DOM, and sets the ref (I assume that is this.resizer) to null or undefined, that does not destroy the Observable that is bound to that element. In fact, I don't even think it removes it from memory, even if it's removed from the DOM! That means that this.resizerDrag$ will never evaluate to false/null, and it will still be listening to an element that is no longer in the DOM.
If that is the case, something like this in componentWillUpdate might help:
if (!this.resizerDrag$ && this.resizer) {
this.resizerDrag$ = // second Observable from above
}
else if (!this.resizer && this.resizerDrag$) {
this.resizerDrag$ = null;
}
This will remove the Observable if the resizer object ceases to exist, that way we can properly reinitialise it upon it's return. There's a better to way to do with Subjects, keeping the subscription to one subject and just subscribing the subject to different mousedown streams once they become available, but let's keep this simple :).
This is something where we'd have to see the rest of your code (for this component) tell what's going on, and figure how to address it. But, my hypothesis is that you'd need to intentionally destroy the Observable if this.resizer is ever removed.
the second Observable to reliably work
Pretty sure that once the above two issues work, this one goes away. Nice and easy!
The CodePen
Here is the very naive mockup I made of this problem:
https://codepen.io/anon/pen/KmapYZ
Drag the blue circles back and forth along the X axis. (Has some little problems and bugs unrelated to the scope of this question, so I'm not worried about them.)
I made some slight changes of course just to keep it in-step with the more dumb downed approach I used. But all the concepts are there, as well as most of the code you wrote, modified to match this approach.
As I mentioned before, I didn't encounter the problem of the dragging only working once, so this better demonstrates the solution to pausing the first Observable. I re-use the dragging element, which I assume is why I didn't run into the 'drag-only-once' problem.
I hope that you or anyone else can comment with some improvements to this approach, or just show us a better (potentially more idiomatic) approach.

RxJS proper way of Creating Behavior Subjects from other Behavior Subjects?

So I'm using an observable values in an angular application, and I want to make several behavior subjects derived from other behavior subject. I was transforming my behavior subjects with the .map() operator, but found out that I could not reference .value. I wanted to be able to reference the current value as was emitted last (so passed through the mapping function). A little digging around with the output of foo.map() I found I could get the functionality I wanted with:
let foo = /* some BehaviourSubject */
let bar = foo.map((x) => x / 2)
bar.operator.project(bar.destination.value) // to get the value as last emitted
But thats not very nice looking
Currently I'm doing something that looks like this to get the functionality i want:
foo = /* some observable*/
bar = foo.map((x) => x / 2).toBehaviorSubject()
foobar = bar.map((y) => y > 10).toBehaviorSubject()
toBehaviorSubject() is a function I've defined as the following
rx.Observable.prototype.toBehaviorSubject = function (initialValue) {
initialValue = initialValue || null
let subject$ = new rx.BehaviorSubject(initialValue)
this.subscribe((value) => { subject$.next(value) })
return subject$
}
I had earlier toyed with this as a solution, but opted for what I've shown above:
foo = /* some BehaviourSubject */
bar = new rx.BehaviorSubject( foo.value / 2))
foo.subscribe( (x) => {
bar.next(x / 2)
})
foobar = new rx.BehaviorSubject(bar.value > 10)
bar.subscribe( (y) => {
foobar.next(y > 10)
})
These work and all, but I have to ask, is there a standard convention for something that works like the above two examples?
Edit-------------------
Some added context might be helpful.
so I have a BehaviorSubject auth.User$ that is sourced from a service I wrote for window.localstorage access which hands out BehaviorSubjects on its localStorage.get(key) function. I wrote this wrapper to deal with the fact that the localStorage change event fires on all tabs except the tab that changed the value.
Some parts of my application need to know whether the user has been initialized, or if the user is an anonymous user (some portlets can be accessed without logging in) or authenticated (for those which require the user to be logged in), and when these statuses change. In order to avoid duplicating the logic for producing the boolean values for isInitialized, isAnonymous, and isAuthenticated, I wanted to derive more BehaviorSubjects from auth.User$. I want them to be BehaviorSubjects specifically because some of the parts of the application only need the values on an on-call basis, and so being able to reference auth.isAuthenticated$.value is preferable to subscribing to that observable.
I used the Observable.map() function because I wanted to have observable values that fire when auth.user$ does and which transform the emitted values from it, but would like it to still be a BehavorSubject as mentioned above.
So my question is essentially: is there a standard convention for applying a transformation/mapping function to a BehaviorSubject and still get a BehaviorSubject?
I am not sure I understand your question, but basically a behaviour subject always has a value, so you can query the subject from that value at any point of time. I believe in Rxjs v5, getValue is the relevant method.
When you do let foo = /* some BehaviourSubject */ let bar = foo.map((x) => x / 2), then bar is not a subject anymore, it is an observable, i.e. a producer of a stream of values. You need to subscribe to bar to start that producer and actually get a value. Your API seems to do just that. A shorter way is to do bar.subscribe(anotherBehaviourSubject).
Now, do you really need to start the producer so early? i.e. do you actually need a behaviour subject in the first place? If you do, then of course go ahead.

quering for objects with angularFireCollection?

I used the implicit method for retrieving data objects:
setData = function(segment){
var url = 'https://myFireBase.firebaseio.com/';
var rawData = angularFire(url+segment,$rootScope,'data',{});
rawData.then(function(data){
// sorting and adjusting data, and then broadcasting and/or assinging
}
}
This code is located inside a service that gets called from different locations, by development stages it'll probably be around 100 - 150 so I got out of the controllers and into a service, but now firebase data-binding would obviously over-write the different segments so I turned back to explicit methid, to have the different firebases only sending the data to site instead of data-binding and over-writing each other:
var rawData = angularFireCollection(url+segment);
And right there I discovered why I chose the implicit in the first place: There's an argument for the typeof, i could tell firebase if I'm calling a string, an array, an object etc. I even looked at the angularfire.js and saw that if the argument is not given, if falls back to identifying it as an array by default.
Now, I'm definitely going to move to the explicit method (that is, if no salvation comes with angular2.0), and reconstructing my firebase jsons to fit the array-only policy is not that big of a deal, but surely there's an option to explicitly call objects, or am I missing something?
I'm not totally clear on what the question is - with angularFireCollection, you can certainly retrieve objects just fine. For example, in the bundled chat app (https://github.com/firebase/angularFire/blob/gh-pages/examples/chat/app.js#L5):
$scope.messages = angularFireCollection(new Firebase(url).limit(50));
Each message is stored as an object, with its own unique key as generated by push().
I'm also curious about what problems you found while using the implicit method as your app grew. We're really looking to address problems like these for the next iteration of angularFire!

Infinite Loop caused by Append?

I have a bit of a question regarding why my code seems to hang when I run it. The code is for a project I have in a class, but we spent one class period going over Prolog so much of what I've learned is stuff I've searched around for and have taught myself. I do apologize if my code contains horrendous stylistic errors, but again, as we never formally learned how we 'should' use Prolog, this is based mostly on my own experimentation.
The goal of the segment of code I am writing is, more or less, to form a chain that connects one actor to another through a series of movies that they have been in.
I have a function I am calling that is meant to construct connections between a starting actor, all possible linked actors ending actor, and the list of movies that connects them. This is probably a horribly inefficient method of doing this, however implementing it this way solves two parts of the assignment with one segment of code.
The code that calls the function works, and for the sake of making this simpler to read, I will omit it unless asked to share it. In short, it asserts a globalStartingActor, and passes on two empty lists (ActorList = [] and MovieList = []) to a function doActorAssertions.
In turn, we have doActorAssertions. This is the revised version of it, which should be simplified and easier to read, but lacks the massive commenting that it had previously.
doActorAssertions(ActorsName,ActorList,MovieList) :-
isNotInList(ActorsName,ActorList) ->
(
findMoviesIn(ActorsName,MoviesIn),%finds all movies ActorsName is in
howLong(MoviesIn,LenMoviesIn),%Sees how many movies there are.
(
LenMoviesIn ==0;
(
append(ActorsName,ActorList,UpdatedActorList),%this causes errors!
globalStartingActor(GSAName),%asserted starting actor
assert(connectedActors(GSAName,ActorsName,MovieList)), %says that the GSAName is connected to ActorsName by a list of movies MovieList.
write(actorAsserted),
addAndTraverse(MoviesIn,UpdatedActorList,MovieList) %Goes to propegate all movies the actor is in, then actors in those movies, then recursively calls this function again.
)
)
),
true.
As I said previously, the append tag seemed to be the source of the error! This indeed appears to be the case when I simplify the code to what it is above. I simply comment that append out, and the code body works.
Why, then, is append preventing the code from working properly? I need to have append (or similar function) in that part of the code!
Is ActorsName a list? The variable' name suggests it is, as well as the usage in append/3, but then what isNotInList(ActorsName,ActorList) means? Partial or full disjunction? This could be the cause of the endless loop, maybe you should use the difference of those sets to increment the ActorList.
You should try to avoid assert/1, and instead pass around the state in variables. See this other answer for a schema doing something very similar to what you are attempting here.
This is useless, could be a typo, but then I don't understand the ->
...
),
true.
I think should read
...
); % note the semicolon!
true.

Resources