DEV Community

Riturathin Sharma
Riturathin Sharma

Posted on

Implementing mergeMap and switchMap: "The React Way"

Recently I came across a problem where I had to implement the following functionality:

  1. A dasboard app that shows charts data of trading units
  2. There is a filter section which allows user to select the timeframe: hourly, weekly, monthly etc

From a developer's mindset its easy:-

  1. Call the API with the timerange
  2. Fetch the response asynchronously
  3. Render the new chart

All goes smoothly until....

This question struck my mind

"What if the user quickly switches between timeframes ?"

The answer to this lies in the mergeMap and switchMap implementation of RxJs

mergeMap - ✘
switchMap - ✓

The reason is mergeMap allows multiple requests to run in parallel but doesn't ensure the response is in order.

Think of it like this:

You go to a foodcourt and go to different restaurants to place order:

  1. KFC- This order takes 15 mins
  2. Domino's- This takes 10 mins
  3. Taco - This takes 20 mins

You sit on the table waiting for the orders patiently. You get happy to see the food on your table and have ENOUGH TIME to feast, but not interested in the order in which they reach you.

This is mergeMap in RxJS

switchMap on the other hand cancels the other requests keeping the latest one

Example of this:

You go to a foodcourt and go to different restaurants to place order:

  1. KFC- This order takes 15 mins, you place the order
  2. Domino's- This takes 10 mins, you place the order
  3. Taco - This takes 20 mins, you place the order

But... here is the catch. You suddenly get a phone call and you have time to munch on one order only. So, you cancel all the previous orders and decide to keep the last one from Taco

this is switchMap in RxJs.

Now, since we are clear on the technical aspect, the next question is "Can we draw a parallelism on React and achieve the same?"

Certainly! The answer lies in the useEffect and AbortController mechanism of React

Basically there are two approaches

*1. First the React Way: *

 useEffect(() => {
    const controller = new AbortController();
    fetch(`/api?timeframe=${timeframe}`, {
   signal: controller.signal,
}).then( res => res.json())
  .then( setData(res))
  .catch( error => { 
if( error.name === 'AbortError' ) throw error;
});

return () => controller.abort();
}, [range]);
Enter fullscreen mode Exit fullscreen mode
  1. The second approach:
let requestId = 0;

 useEffect(() => {
  const id = ++requestId;
    fetch(`/api?timeframe=${timeframe}`)
.then( res => res.json())
  .then( data => {
   if( id === requestId ) {
    setData(data);
}
});


}, [range]);
Enter fullscreen mode Exit fullscreen mode

First approach , we use AbortController. User selects a new timeframe and the previous request gets cancelled. UI updates only with the new request

Second approach, we maintain ids to check if its the latest request. All requests run but only latest response is applied.

This left me with one critical thinking. It is not necessary to use specific library for performing specific functions. Because it adds to the overall bundle size. There is always a better and simpler way!

Open for thoughts

Top comments (0)