Chapter 16: RxJS and Reactive Programming
Angular’s HttpClient, forms, router, and event streams all rely on RxJS (Reactive Extensions for JavaScript). Understanding RxJS is essential for mastering Angular.
This chapter will focus on the theory of reactive programming with RxJS, building a solid foundation before diving into practical patterns later.
16.1 What is Reactive Programming?
Reactive programming is about dealing with data streams (values that arrive over time).
Examples of streams:
- User clicks.
- HTTP responses.
- WebSocket messages.
- Timer events.
Instead of pulling data (asking for it), we react when data arrives.
16.2 Observables
An Observable is a lazy, push-based collection.
- Lazy: nothing happens until you subscribe.
- Push-based: values are delivered as they become available.
Think of an Observable as a producer of values:
import { Observable } from 'rxjs';
const obs = new Observable(observer => {
observer.next(1);
observer.next(2);
setTimeout(() => observer.next(3), 1000);
observer.complete();
});
16.3 Subscriptions
To consume an Observable, you subscribe:
obs.subscribe({
next: value => console.log(value),
error: err => console.error(err),
complete: () => console.log('Done')
});
Output:
1
2
3 (after 1s)
Done
16.4 Hot vs Cold Observables
- Cold: starts producing values when you subscribe (e.g.,
http.get()). - Hot: produces values regardless of subscription (e.g.,
fromEvent(document, 'click')).
This distinction is important for performance and side-effects.
16.5 Subjects
A Subject is both an Observable and an Observer. It allows multicasting values to many subscribers.
import { Subject } from 'rxjs';
const subject = new Subject<number>();
subject.subscribe(v => console.log('A:', v));
subject.subscribe(v => console.log('B:', v));
subject.next(1); // A:1 B:1
subject.next(2); // A:2 B:2
Special subjects:
- BehaviorSubject: keeps the latest value.
- ReplaySubject: replays a set number of values to new subscribers.
- AsyncSubject: emits the last value only when complete.
16.6 Operators
Operators are pure functions that transform streams.
They are what make RxJS powerful.
Categories of operators:
-
Creation operators (make observables):
of(1,2,3),from([1,2,3]),interval(1000),fromEvent(...).
-
Transformation operators:
map,mergeMap,switchMap,concatMap.
-
Filtering operators:
filter,take,skip,debounceTime,distinctUntilChanged.
-
Combination operators:
merge,concat,combineLatest,forkJoin,withLatestFrom.
-
Error handling operators:
catchError,retry,retryWhen.
-
Utility operators:
tap,finalize,delay.
Example: map
of(1, 2, 3).pipe(
map(x => x * 10)
).subscribe(console.log);
// Output: 10, 20, 30
Example: switchMap
fromEvent(document, 'click').pipe(
switchMap(() => http.get('/data'))
).subscribe(data => console.log(data));
- Cancels previous request if another click happens.
- Useful for search/autocomplete.
16.7 Marble Diagrams
RxJS uses marble diagrams to visualize operators.
Example:
- Source:
--1--2--3--| map(x => x*10)- Output:
--10--20--30--|
These diagrams help understand how operators manipulate time-based streams.
16.8 RxJS in Angular
Angular integrates RxJS deeply:
- HttpClient: returns Observables.
- Forms:
form.valueChangesis an Observable. - Router:
ActivatedRoute.paramsis an Observable. - AsyncPipe: subscribes/unsubscribes automatically.
16.9 Signals vs RxJS
Signals (Angular v16+) offer a simpler reactive model for local state.
RxJS is still essential when:
- You work with async streams (clicks, websockets, HTTP polling).
- You need complex transformations (debouncing, combining streams).
Rule of thumb:
- Use signals for state.
- Use RxJS for streams.
- Combine both when needed (
toSignal()bridge).
16.10 Summary
- RxJS brings reactive programming to Angular.
- Observables are push-based collections of values over time.
- Subscriptions let you consume observables.
- Subjects allow multicasting and state handling.
- Operators transform, filter, and combine streams.
- RxJS complements signals: both are core to modern Angular.