In a masstransit saga I can make a request like so:
When(ReadyToDepart)
.Request(TaxiToRunway,
(context) => context.Init<TaxiToRunway>(new {CorrelationId = context.Saga.CorrelationId}))
I am struggling to work out how to express this as part of a WhenEnter.
WhenEnter(Taxiing, context =>
context.Request(TaxiToRunway, c => c.Init<TaxiToRunway>(new {c.Saga.CorrelationId})));
Doesn't compile. There doesn't seem to be an overload for Request that works with message initializers. What should this look like?
Related
I have a component that should listen to some socket events. I register them as follows to avoid spurious register/unregister actions of the event listeners (socketListen returns the destruction of the listener itself, so that is taken care of).
useEffect(() => socketListen('name', newName => setName(newName)), []);
Now as I have more of these kind of listeners, I want to get rid of boilerplate code by writing a custom hook
const useListener = (event, callback) => {
useEffect(() => socketListen(event, callback), [event, callback]);
};
to be then used as
useListener('name', newName => setName(newName));
intending to put focus on the actual action performed and not on the useEffect invokation.
Now the issue is that I hand over a closure (invoking the state setter setName) to my custom hook which implies that the callback in useListener is changed on rerender and therefore again generates spurious listener registering/unregistering. To salvage I could wrap the closure in a useCallback but that would defy my original goal of reducing the code clutter.
I think I can see the functional reason for above problem (and hope to have conveyed that in my writing), but I wonder if there is a convenient way to write a helper function to do what I intended to accomplish with useListener without additional boilerplate code. My actual code uses more complex closures, but I hope that this example suffices to pinpoint my issue.
You should be able to bail out of the requirement for a memoized closure by using a reference:
const useListener = (event, callback) => {
const ref = useRef();
ref.current = callback;
useEffect(() => (
socketListen(event, newName => ref.current(newName))
), [event]);
};
It's important that you write newName => ref.current(newName) instead of just ref.current so that the property access ref.current doesn't occur until the socketListen callback is invoked. That way ref.current is equal to the most recent callback passed to useListener() and isn't referencing the stale closure from the first call to useListener().
In many articles I find that tap operator is a good way to perform side effects. My question is about a difference between performing side effects using subscribe and tap. Here are examples which are doing actually the same:
this.store$
.pipe(tap(x => {
this.store = x;
}));
this.store$
.subscribe(x => {
this.store = x;
});
Is there any difference in the performance or is there any reason to use one of these approaches?
In Angular context.
You may have a component say MyComponent. There is a service as well for this component MyService. This service is responsible for some complex operation in MyComponent. Now you will make the subscription in the MyComponent as
$myObs.subscribe((val) => //do something );
But same data may be required in your service as well, so you define it in service as
$myObs.pipe(tap((val) => // do something with data in service));
Subscription will be done in component but using tap you can assign data member variable in your service as well.
Because BehaviorSubject extends Subject and Subject extends Observable, all of those three have static .create(observer) method to create them using custom values emission logic.
I' able to use with good result Observable.create(observer), for instance:
a = Rx.Observable.create(obs => {
setInterval(() => {
obs.next('tick');
}, 500)
})
s = a.subscribe(v => console.log(v))
Gives me expected output (tick every 500ms)
But when I replace Observable with Subject/BehaviorSubject, it's not so willing to get up and running:
a = Rx.Subject.create(obs => {
setInterval(() => {
obs.next('tick');
}, 500)
})
s = a.subscribe(v => console.log(v)); // Nothing
a.next(5); // Still nothing
Basically, subject seems to work as intended to only if they are created via new operator like below:
a = new Rx.Subject();
s = a.subscribe(v => {console.log(v)});
a.next(5) // Ok, got value here
Even if I try to use non-parametrized create method, which invocation shall boil down to same result as using new:
a = Rx.Subject.create();
I'm still unable to force it to emit values.
I'm aware that subjects are designed to receive values from outside world (not to generate them internally as Observables), thus subject shall be triggered by external code with subject.next('value'), but I was just curios that if they are strictly related to Observables, logic behind create and further behavior shall be same...
Can anyone explain, why usage of create on Subject (even if they are not designed to work this way, but still it shall be possible) does not work as supposed to?
I'am currently switched from promises to observables. I am using Redux-Observable for my react app. Basically, I am looking for the best operator that will enable mutliple, concurrent ajax calls and return the responses when all the observables have sucessfully finished executing.
Here is a code snippet from my app.
let epicPostAd = (action$, store, {ajax}) =>
action$.ofType(POST_AD)
.debounceTime(1000)
.mergeMap(({ payload }) =>
ajax(generateAjaxRequestSetting(POSTS_URL, 'post', payload,CT_JSON))
.map(response => postAdSuccessful(response))
.catch(e => Observable.of(postAdUnsuccessful(e.xhr.response)))
.takeUntil(action$.ofType(LOCATION_CHANGE))
)
It is a simple ajax request that posts given ad and dispatches POST_AD_SUCCESSFUL when response is 201 else dispatches POST_AD_UNSUCCESSFUL on error.
But the issues is I want to make subsequent ajax observable stream when there is a response. Such as
.map(response => /* start a stream of ajax observables then process the response */)
I will appreciate if you show me the optimal way of achieving this.
Sounds like you're looking for the forkJoin operator.
It will subscribe to all the Observables you pass to it and after they all complete, it will emit the last value from each inside an array.
It wasn't entirely clear where in your Epic you wanted to do this, so I just made a generic example:
const somethingEpic = (action$, store, { ajax }) =>
action$.ofType(SOMETHING)
.mergeMap(() =>
Observable.forkJoin(
ajax('/first'),
ajax('/second'),
ajax('/third')
)
.do(results => {
// the results is an array, containing each
const [first, second, third] = results;
console.log(first, second, third);
})
.map(results => ({
type: 'SOME_RESULTS',
results
}))
);
Technically, it supports a final resultSelector argument you can use instead of using the map operator after it, but I tend not to use it because I've found it's less clear with only negligible performance benefits in common redux-observable style cases. But it's still good to know. Can be handy for more "data-normalization" stuff rather than "transform this into an action" stuff.
const somethingEpic = (action$, store, { ajax }) =>
action$.ofType(SOMETHING)
.mergeMap(() =>
Observable.forkJoin(
ajax('/first'),
ajax('/second'),
ajax('/third'),
results => ({
type: 'SOME_RESULTS',
results
})
)
);
ALSO, if you're asking yourself "what operator do I use?" you should try the operator wizard located in the documentation: http://reactivex.io/rxjs/
Scroll down to the part that says:
Do you need to find an operator for your problem? Start by choosing an option from the list below:
I have one existing Observable, and...
I have some Observables to combine together as one Observable, and...
I have no Observables yet, and...
Hint: open your DevTools to experiment with RxJS.
Though in this case, forkJoin is correctly suggested but when you click on it, it isn't yet documented :sadface: But a google search would present many different websites explaining what it does and how to use it (in RxJS and in other Rx implementations in other languages). Like this helpful website
Here is the answer to my own question. Although JayPhelps answered, I realized that my question was not so clear. Using Jay's recommendation. I came up with the following:
let epicPostAd = (action$, store, {ajax, observable}) =>
action$.ofType(POST_AD)
.debounceTime(1000)
.mergeMap(({ payload }) =>
ajax(generateAjaxRequestSetting(POSTS_URL, 'post', payload, CT_JSON))
.mergeMap(response =>
observable.forkJoin(
ajax(''),
ajax('')
)
.do(res => {
const [first, second, third] = results;
console.log(first, second, third);
})
.map(res => postAdSuccessful(res))
)
.catch(e => observable.of(postAdUnsuccessful(e.xhr.response)))
.takeUntil(action$.ofType(LOCATION_CHANGE))
)
So here how it works. I make a post request and immediately after ajax request finishes execution I .mergeMap the response to a stream of ajax ovservables using .forkJoin(). Then process the results
I'm looking for some guidance on the correct way to setup a WebSocket connection with RxJS 5. I am connecting to a WebSocket that uses JSON-RPC 2.0. I want to be able to execute a function which sends a request to the WS and returns an Observable of the associated response from the server.
I set up my initial WebSocketSubject like so:
const ws = Rx.Observable.webSocket("<URL>")
From this observable, I have been able to send requests using ws.next(myRequest), and I have been able to see responses coming back through the ws` observable.
I have struggled with creating functions that will filter the ws responses to the correct response and then complete. These seem to complete the source subject, stopping all future ws requests.
My intended output is something like:
function makeRequest(msg) {
// 1. send the message
// 2. return an Observable of the response from the message, and complete
}
I tried the following:
function makeRequest(msg) {
const id = msg.id;
ws.next(msg);
return ws
.filter(f => f.id === id)
.take(1);
}
When I do that however, only the first request will work. Subsequent requests won't work, I believe because I am completing with take(1)?
Any thoughts on the appropriate architecture for this type of situation?
There appears to be either a bug or a deliberate design decision to close the WebSocket on unsubscribe if there are no further subscribers. If you are interested here is the relevant source.
Essentially you need to guarantee that there is always a subscriber otherwise the WebSocket will be closed down. You can do this in two ways.
Route A is the more semantic way, essentially you create a published version of the Observable part of the Subject which you have more fine grained control over.
const ws = Rx.Observable.webSocket("<URL>");
const ws$ = ws.publish();
//When ready to start receiving messages
const totem = ws$.connect();
function makeRequest(msg) {
const { id } = msg;
ws.next(msg);
return ws$.first(f => f.id === id)
}
//When finished
totem.unsubscribe();
Route B is to create a token subscription that simply holds the socket, but depending on the actual life cycle of your application you would do well to attach to some sort of closing event just to make sure it always gets closed down. i.e.
const ws = Rx.Observable.webSocket("<URL>");
const totem = ws.subscribe();
//Later when closing:
totem.unsubscribe();
As you can see both approaches are fairly similar, since they both create a subscription. B's primary disadvantage is that you create an empty subscription which will get pumped all the events only to throw them away. They only advantage of B is that you can refer to the Subject for emission and subscription using the same variable whereas A you must be careful that you are using ws$ for subscription.
If you were really so inclined you could refine Route A using the Subject creation function:
const safeWS = Rx.Subject.create(ws, ws$);
The above would allow you to use the same variable, but you would still be responsible for shutting down ws$ and transitively, the WebSocket, when you are done with it.