How to cancel epic to avoid multiple instances

I've got following epic (btw. why epic?)

const fetchOrders = action$ => {
  console.log('fetchOrders', action$);
  return action$.pipe(
    ofType(FETCH_ORDERS),
    mergeMap(action => interval(2000).pipe(
      map(_ => ordersReceived(mockOrders()))
    ))
  );
};

where ordersReceived is an action creator meant to be run with paylod, mockOrders returns some mocked payload.

When I call FETCH_ORDERS action this epic starts then every 2seconds ordersReceived is dispatched and that's fine. But when I've fired this action again I've noticed that the ordersReceived being called more frequent, obviuosly I have created multiple instances that now fire separate actions. Now, is there a way that I could cancel previous epic call?

Edit I've found in the docs about cancellation that I have to use another action that the epic will react e.g.

const fetchOrders = (action$, state) => {
  console.log('fetchOrders', state);
  return action$.pipe(
    ofType(FETCH_ORDERS),
    mergeMap(action => interval(2001).pipe(
      map(_ => ordersReceived(cloneOrders())),


      takeUntil(action$.pipe(
        filter(action => action.type === FETCH_ORDERS_CANCELLED)
      ))


    ))
  );
};

then somewhere call dispatch({type:FETCH_ORDERS_CANCELLED}).

It is fine but I was thinking something more autononymous:) so the call to fetchOrders will stop anything previously called.

Upvotes: 1

Views: 242

Answers (1)

Anas
Anas

Reputation: 5727

switchMap is what you're looking for. it will cancel the previous observable and emit the values of the new one.

const fetchOrders = action$ => {
  console.log('fetchOrders', action$);
  return action$.pipe(
    ofType(FETCH_ORDERS),
    switchMap(action => interval(2000).pipe(
      map(_ => ordersReceived(mockOrders()))
    ))
  );
};

Upvotes: 1

Related Questions