Redux Observable: How to return an action from a callback?
I am using the WebRTC library which has a very specific API. The second argument to the method peerConnection.setRemoteDescription
should be a callback when it finishes setting the remote description:
This is one of my wrapper functions for my WebRTC class:
export function setRemoteSdp(peerConnection, sdp, callback) {
if (!sdp) return;
return peerConnection.setRemoteDescription(
new RTCSessionDescription(sdp),
callback, // <-------------
);
}
And this is a sketch of what I want to do:
function receivedSdp(action$, store) {
return action$.ofType(VideoStream.RECEIVED_SDP)
.mergeMap(action => {
const {peerConnection} = store.getState().videoStreams;
const {sdp} = action.payload;
return WebRTC.setRemoteSdp(peerConnection, sdp, () => {
return myReducer.myAction(); // <------ return action as the callback
})
})
};
This doesn't work as I am not returning Observable. Is there a way to do this?
PS this is the WebRTC API: https://github.com/oney/react-native-webrtc/blob/master/RTCPeerConnection.js#L176
source to share
So, the problem is what setRemoteSdp
does not return Observable, but myReducer.myAction()
does, and what Observable do you want to combine?
You can use Observable.create
and wrap the call WebRTC.setRemoteSdp
:
.mergeMap(action => {
return Observable.create(observer => {
WebRTC.setRemoteSdp(peerConnection, sdp, () => {
observer.next(myReducer.myAction());
observer.complete();
})
});
}
.mergeAll()
Observable.create
returns an Observable that emits another Observable from myReducer.myAction()
. Now I have a so called higher order which I want to flatten with mergeAll()
( concatAll
will work too).
source to share
Martin's answer is correct using Observable.create
or new Observable
is the same (except that it is not clear to me why you need mergeAll()
it since it mergeMap
will flatten?)
As a bonus, you can also use Observable.bindCallback
for this.
// bindCallback is a factory factory, it creates a function that
// when called with any arguments will return an Observable that
// wraps setRemoteSdp, handling the callback portion for you.
// I'm using setRemoteSdp.bind(WebRTC) because I don't know
// if setRemoteSdp requires its calling context to be WebRTC
// so it "just in case". It might not be needed.
const setRemoteSdpObservable = Observable.bindCallback(WebRTC.setRemoteSdp.bind(WebRTC));
setRemoteSdpObservable(peerConnection, sdp)
.subscribe(d => console.log(d));
Usage inside your epic would be something like this
// observables are lazy, so defining this outside of our epic
// is totally cool--it only sets up the factory
const setRemoteSdpObservable = Observable.bindCallback(WebRTC.setRemoteSdp.bind(WebRTC));
function receivedSdp(action$, store) {
return action$.ofType(VideoStream.RECEIVED_SDP)
.mergeMap(action => {
const {peerConnection} = store.getState().videoStreams;
const {sdp} = action.payload;
return setRemoteSdpObservable(peerConnection)
.map(result => myReducer.myAction());
})
};
You can use this to create an Observable wrapper for the entire WebRTC apis.
source to share