RxJS scan and filter vs bufferCount issue

97 views Asked by At

I encountered a problem when playing with ngrx effect and rxjs. I am using two versions of effect (simplified for purpose of this question):

Version 1:

public effect$ = createEffect(() =>
    this.actions$.pipe(
      ofType(
        actions.successAction1,
        actions.successAction2,
        ...
      ),
      scan((actionCount, typedAction) => actionCount + 1, 0),
      filter((actionCount) => actionCount === 2), // If more actions, then this value is different
      map((actionCount) => actions.finalAction())
    )
  );

Version 2:

public effect$ = createEffect(() =>
    this.actions$.pipe(
      ofType(
        actions.successAction1, 
        actions.successAction2
        ...
      ),
      bufferCount(2), // If more actions, then this value is different
      switchMap(() => actions.finalAction())
    )
  );

I really do not understand why first version is working, and second is not. I expect the "finalAction" to be dispatched after 2 actions (succcessAction1 and successAction2) are dispatched.

1

There are 1 answers

1
Abhilash Asokan On

In the first version, you are using the scan operator to accumulate a count of actions, and then using the filter operator to check if the count is equal to 2 before dispatching the final action. This works as expected because the scan operator maintains state and continuously updates the count with each incoming action.

In the second version, you are using the bufferCount(2) operator, which buffers the last 2 emitted values and emits an array containing those values. However, you are missing a key point in the second version: the bufferCount(2) operator does not emit an array for every two actions. Instead, it emits an array after every two values emitted by the source observable.

To achieve the desired behavior in the second version, you need to modify it as follows:

public effect$ = createEffect(() =>
    this.actions$.pipe(
      ofType(
        actions.successAction1, 
        actions.successAction2
        ...
      ),
      bufferCount(2),
      filter(actionsArray => actionsArray.length === 2), // Check if the array contains two actions
      switchMap(() => actions.finalAction())
    )
);

By adding the filter(actionsArray => actionsArray.length === 2) after bufferCount(2), you ensure that the final action is only dispatched when there are exactly two actions in the buffered array. This should now behave similarly to the first version with scan and filter.