How to Use tap Operator in RxJS for Side Effects
Use the
tap operator in RxJS to perform side effects such as logging or debugging inside an observable chain without modifying the emitted values. It takes a function that runs on each emission but passes the original data unchanged downstream.Syntax
The tap operator is used inside an RxJS pipe to run side-effect code on each emitted value without changing the stream.
tap(nextFn): RunsnextFnon each emitted value.tap({ next, error, complete }): Runs callbacks for next value, error, and completion.
typescript
import { tap } from 'rxjs/operators'; observable$.pipe( tap(value => { // side effect code here }) );
Example
This example shows how to use tap to log values emitted by an observable without changing them.
typescript
import { of } from 'rxjs'; import { tap, map } from 'rxjs/operators'; const source$ = of(1, 2, 3); source$.pipe( tap(value => console.log('Before map:', value)), map(value => value * 10), tap(value => console.log('After map:', value)) ).subscribe(finalValue => { console.log('Subscriber received:', finalValue); });
Output
Before map: 1
After map: 10
Subscriber received: 10
Before map: 2
After map: 20
Subscriber received: 20
Before map: 3
After map: 30
Subscriber received: 30
Common Pitfalls
Common mistakes when using tap include:
- Trying to modify the emitted value inside
tap. It does not change the stream data. - Using
tapfor asynchronous side effects without handling timing properly. - Confusing
tapwithmapwhich transforms data.
typescript
import { of } from 'rxjs'; import { tap, map } from 'rxjs/operators'; // Wrong: modifying value inside tap (does NOT affect output) const wrong$ = of(1).pipe( tap(value => { value = value * 10; }), ); wrong$.subscribe(value => console.log('Wrong output:', value)); // Right: use map to transform values const right$ = of(1).pipe( map(value => value * 10), tap(value => console.log('Right output:', value)) ); right$.subscribe();
Output
Wrong output: 1
Right output: 10
Quick Reference
Use tap to:
- Run side effects like logging or debugging.
- Inspect values without changing them.
- Handle next, error, and complete callbacks.
Remember: tap does not modify the stream data.
| Usage | Description |
|---|---|
| tap(nextFn) | Run a function on each emitted value without changing it |
| tap({ next, error, complete }) | Run callbacks for next value, error, and completion events |
| Use with pipe() | Place inside observable pipe to add side effects |
| Do not modify values | tap should not change emitted data, use map for that |
Key Takeaways
Use tap to perform side effects without altering the observable data.
tap runs a function on each emitted value inside the pipe.
Do not modify values inside tap; use map to transform data.
tap can handle next, error, and complete callbacks.
tap is great for logging and debugging observable streams.