jeanpaul62
jeanpaul62

Reputation: 10571

Converting redux-saga to redux-observable

I am pretty new to reactive programming, and would like to translate the following piece of code from redux-saga to redux-observable.

The idea is to wait for some API call, wait 5s and dispatch another action.

function* mySaga(action) {
  const response = yield call(someApiCall);
  yield call(delay, 5000);
  yield put({ type: 'ACTION' });
}

Here's how I would have done it in redux-observable:

action$
  .ofType('SOME_ACTION')
  .mergeMap(someApiCall)
  .delay(5000)
  .map(() => ({ type: 'ACTION' }))

Upvotes: 2

Views: 606

Answers (1)

jayphelps
jayphelps

Reputation: 15401

Your translation is accurate, assuming you omitted the yield takeEvery('SOME_ACTION', mySaga) stuff in your original example.

I would however recommend isolating your Observable chain; put all the stuff to apply after someApiCall(), inside the mergeMap:

action$
  .ofType('SOME_ACTION')
  .mergeMap(action =>
    someApiCall()
      .delay(5000)
      .map(() => ({ type: 'ACTION' }))
  )

Even though it makes no functional difference in your example, if you or a team member later comes in and tries to add error handling it critical you don't let the error bubble outside the mergeMap:

action$
  .ofType('SOME_ACTION')
  .mergeMap(action =>
    someApiCall()
      .delay(5000)
      .map(() => ({ type: 'ACTION' }))
      .catch(error => Observable.of({
        type: 'SOME_ACTION_FAILED',
        payload: error
      }))
  )

If you had placed the catch on the top-level Observable, after the mergeMap, the error would bubble to the top-level chain and although you would catch the error, your epic would no longer be listening for future actions.

If it isn't clear why, I recommend learning more about how Observables + operators work--I promise isn't not that scary! Here's a great video that even touches on "isolating your observable chains" to catch errors at the correct point. https://youtu.be/3LKMwkuK0ZE?t=20m15s

Upvotes: 3

Related Questions