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

+3


source to share


2 answers


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).

+2


source


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.

+2


source







All Articles