#rxjs #tutorial #intermediate

Day 6: Transformation Operators (scan, reduce)

Day 6: Accumulating Data

How do we maintain state in a stream? Like “Total Price” or “Current Score”? We use accumulation operators.

1. scan

The RxJS equivalent of Array.reduce, but it emits every intermediate result. Ideally suited for managing state over time (like a Redux store).

import { of } from 'rxjs';
import { scan } from 'rxjs/operators';

const numbers$ = of(1, 2, 3);

numbers$.pipe(
  // (accumulator, current) => newAccumulator
  scan((total, n) => total + n, 0) // Start with 0
).subscribe(console.log);

// Output:
// 1  (0 + 1)
// 3  (1 + 2)
// 6  (3 + 3)

Real World: Tracking a click count.

fromEvent(document, 'click').pipe(
  map(() => 1),
  scan((acc, curr) => acc + curr, 0)
).subscribe(count => console.log('Click count:', count));

2. reduce

Works exactly like scan, but waits for the Observable to complete and emits only the final result.

import { of } from 'rxjs';
import { reduce } from 'rxjs/operators';

of(1, 2, 3).pipe(
  reduce((total, n) => total + n, 0)
).subscribe(console.log);

// Output:
// 6

Note: reduce emits nothing if the source never completes (like an interval or click listener).

3. mapTo (Deprecated but common)

Often replaced by map(() => value). It simply maps every emission to a constant.


Homework for Day 6:

  1. Create an interval that emits every 100ms.
  2. Use scan to accumulate the values into an array.
  3. Use take(5) to stop it.
  4. Output should look like: [0], [0, 1], [0, 1, 2]

Get ready. Day 7 is the big one. Flattening Maps (switchMap, mergeMap).