Let’s imagine we have a simple scenario. A request to the server that on success or on fail we will dispatch some actions to update our reducer.

Let’s see how such case would be in code.

Let me break it down a bit.

In the above example we define a new epic. Then using ofType we are waiting the action with type ACTION_REQUEST to get fired. When that is triggered we go to switchMap that here we limit the request that we are getting. Switch map run one request per time so anyone else will be ignored, this way you avoid multiple requests. Then with from we are transforming the promise request to an observable. Lastly we are using mergeMap to fetch the response (imagine a .then on a promise) and we return the set of actions and we do the same with the Error.

What if you want to first show a loading to indicate the loading/fetching of the data?

Now you can easily add an action before requesting data.

We are using concat that will run the two actions in it (loadingList and then the request) in the order defined. Getting easier?

Now you have all that ready and you are using redux forms to handle your data. How you will know when you press submit in that beautiful form of yours that is getting submitted status to show that loading animation? Well the idea remains the same. Let see how something like this can be accomplished.

Here we change a bit the logic. Again we are waiting for the same action on the ofType section. At this example we will want the formName to be passed to the Epic in order to do the actions shown above. In the switchMap we are expecting two things, a payload and a meta! Yes a meta. Meta hold the logic that payload doesn’t have to know about. You can see here more details on why and when to use it. So again using concat and the redux form action startSubmit we can defined that our form started submitting something. Don’t forget to stopSubmit on both success and error. That’s it !

I would suggest that you would always have a request action dispatched with that name like the examples ACTION_REQUEST or FETCH_BLAH_LIST_REQUEST. This way you would always know that this is an epic based action for side effects.

You can now use takeUntil and stop listening to any success event after that event occur. This helps with the classic Netflix problem. When you are navigating to a details page start fetching you are going back and to another details page and the first page start resolving and messing your current page.

This problem is well explained here from Jay Phelps and i recommend you to take a look.

Now we have the same example as before but we only put the takeUntil operator. Now if this listens for the PAGE_CHANGED action it will not cancel the request but it will ignore any resolving of the current request. Yay !! Now if you want you can implement a cancelable request with axios, fetch or anything.

Testing on RxJS with ease

I found the redux-observable tutorials a bit advanced and confusing on testing. I can see why but in most of the cases you would not need such thing so i will propose a simple solution for testing.

Redux observable gives us from the modules two things ActionsObservable and StateObservable. You can use them to create observables for testing. We are using those because on the library the actions that are passing through the epics are created with those actions so because we will try to compare those two they need to be exactly the same.

Let’s try to test our first example.

Here we define two things an action$ that would be an observable with the action that triggers the epic and the expected variable that would be the array of actions that we expect that the epic will return. Furthermore we mock an axios (fetch, axios whatever you have for http requests) resolve with a mocked response. Lastly and this is where it gets interesting we pass that action$ to the epic we want to test, we transform the results of that epic to an array with .pipe(toArray()) and then we make it a promise with .toPromise() so we can await for it to finish with async await. Now we can easily compare what epic returned to what we are expecting !

Here is what a test on the error of that request should look like

With that technique you can easily test any epic and fix the expectations of each.