π RxJS Fundamentals: The Stream Theater
Imagine youβre watching a theater show. Actors perform on stage, you watch from your seat, and the show goes on. RxJS works exactly like thisβbut with data instead of actors!
π What is RxJS?
Think of a water slide at a water park. Water flows down, and you can slide with it. RxJS is like having a magic water slide for your data!
RxJS = Reactive Extensions for JavaScript
It helps you work with data that arrives over timeβlike:
- Button clicks
- Messages from a server
- Timer ticks
// Data flowing like water
import { of } from 'rxjs';
const waterSlide$ = of(1, 2, 3);
// 1, 2, 3 slide down one by one!
π¬ Observable Basics: The Movie Projector
An Observable is like a movie projector. It has a movie ready to play, but nothing happens until someone presses βPlay.β
graph TD A["π¬ Observable<br>Movie Ready"] --> B["βΆοΈ Subscribe<br>Press Play"] B --> C["π Observer<br>Watches Movie"] C --> D["πΊ Data Flows<br>Movie Plays"]
Creating Your First Observable
import { Observable } from 'rxjs';
// The movie projector
const movie$ = new Observable(
subscriber => {
subscriber.next('Scene 1');
subscriber.next('Scene 2');
subscriber.next('The End');
subscriber.complete();
}
);
Key Points:
- Observable = The projector with the movie
- next() = Shows the next scene
- complete() = Movie finished!
- Nothing plays until you subscribe
π Observer Pattern: The Audience
An Observer is like a person sitting in a movie theater. They:
- Watch what happens (next)
- Notice if something breaks (error)
- Know when itβs over (complete)
// The audience member
const movieWatcher = {
next: scene =>
console.log('Watching:', scene),
error: problem =>
console.log('Oops:', problem),
complete: () =>
console.log('Movie ended!')
};
// Press play!
movie$.subscribe(movieWatcher);
The Three Callbacks:
| Callback | What It Does | Real Life Example |
|---|---|---|
next |
Receives data | Getting a text message |
error |
Handles problems | Phone battery dies |
complete |
Stream finished | Conversation ended |
π« Subscription Management: Your Movie Ticket
A Subscription is like your movie ticket. It connects you to the show. When you leave, you tear up the ticket (unsubscribe).
graph TD A["π« Subscribe"] --> B["πΊ Receiving Data"] B --> C{Want to stop?} C -->|Yes| D["πͺ Unsubscribe"] C -->|No| B D --> E["β Resources Cleaned"]
Why Unsubscribe?
Imagine leaving a faucet running forever. Bad idea! Same with subscriptions.
import { interval } from 'rxjs';
// A clock ticking every second
const clock$ = interval(1000);
// Start watching
const ticket = clock$.subscribe(
tick => console.log('Tick:', tick)
);
// After 5 seconds, leave!
setTimeout(() => {
ticket.unsubscribe();
console.log('Stopped watching');
}, 5000);
Memory Leak Prevention:
// WRONG - Subscription runs forever!
clock$.subscribe(t => update(t));
// RIGHT - Clean up when done
const sub = clock$.subscribe(
t => update(t)
);
// Later...
sub.unsubscribe();
π₯ Hot vs Cold Observables: Live TV vs Netflix
This is one of the most important concepts! Letβs use TV as our example.
Cold Observable = Netflix π§
- You start from the beginning
- Each viewer gets their own copy
- The show waits for YOU
import { of } from 'rxjs';
// Netflix show - starts fresh each time
const netflix$ = of('Ep1', 'Ep2', 'Ep3');
// Viewer 1 starts from Ep1
netflix$.subscribe(
ep => console.log('A:', ep)
);
// Viewer 2 ALSO starts from Ep1
netflix$.subscribe(
ep => console.log('B:', ep)
);
Hot Observable = Live TV π₯
- Join wherever the show is NOW
- All viewers see the same thing
- You might miss earlier parts
import { Subject } from 'rxjs';
// Live sports broadcast
const liveTV$ = new Subject();
// Viewer 1 joins early
liveTV$.subscribe(
play => console.log('A:', play)
);
liveTV$.next('Goal scored!');
liveTV$.next('Yellow card!');
// Viewer 2 joins late - missed the goal!
liveTV$.subscribe(
play => console.log('B:', play)
);
liveTV$.next('Half time');
// A sees: Goal, Yellow, Half
// B sees: Half (only!)
Quick Comparison:
| Feature | Cold βοΈ | Hot π₯ |
|---|---|---|
| Start | From beginning | Current moment |
| Viewers | Independent | Shared |
| Example | Netflix | Live TV |
| Creates | New producer | Shares producer |
π’ Subject: The Loudspeaker
A Subject is like a loudspeaker in a stadium. It can:
- Receive announcements (act as Observer)
- Broadcast to everyone (act as Observable)
graph TD A["π€ Someone speaks"] --> B["π’ Subject"] B --> C["π€ Listener 1"] B --> D["π€ Listener 2"] B --> E["π€ Listener 3"]
Using a Subject:
import { Subject } from 'rxjs';
// The stadium loudspeaker
const announcer$ = new Subject();
// Fans listening
announcer$.subscribe(
msg => console.log('Fan A:', msg)
);
announcer$.subscribe(
msg => console.log('Fan B:', msg)
);
// Make announcements
announcer$.next('Game starting!');
announcer$.next('Goal!');
// Both fans hear everything!
Key Features:
- β Multicast (many listeners)
- β Can push values manually
- β Late subscribers miss past values
π§ BehaviorSubject: The Scoreboard
A BehaviorSubject is like a stadium scoreboard. It:
- Always shows the current score
- New viewers immediately see the score
- Updates when score changes
graph TD A["π BehaviorSubject"] --> B["Current Value: 3-2"] C["π€ New Fan Arrives"] --> A A --> D["Shows 3-2 immediately!"]
Requires an Initial Value:
import { BehaviorSubject } from 'rxjs';
// Scoreboard starts at 0-0
const score$ = new BehaviorSubject('0-0');
// Fan arrives, sees current score
score$.subscribe(
s => console.log('Fan A:', s)
);
// Output: Fan A: 0-0
// Score updates
score$.next('1-0');
// Output: Fan A: 1-0
// NEW fan arrives late
score$.subscribe(
s => console.log('Fan B:', s)
);
// Output: Fan B: 1-0 (sees current!)
// Check score anytime
console.log(score$.getValue());
// Output: 1-0
Perfect For:
- π Current user state
- π¨ Current theme
- π Current page
- Any βcurrent valueβ scenario
πΌ ReplaySubject: The DVR
A ReplaySubject is like a DVR that records the show. New viewers can rewind and catch up!
graph TD A["πΌ ReplaySubject"] --> B["Records Last N Values"] C["π€ Late Viewer"] --> A A --> D["Replays recorded values!"] D --> E["Then shows live"]
Choose How Many to Replay:
import { ReplaySubject } from 'rxjs';
// DVR that remembers last 2 plays
const dvr$ = new ReplaySubject(2);
dvr$.next('Play 1');
dvr$.next('Play 2');
dvr$.next('Play 3');
// Late viewer joins
dvr$.subscribe(
play => console.log('Late fan:', play)
);
// Output:
// Late fan: Play 2 (replayed)
// Late fan: Play 3 (replayed)
// Then sees future plays live!
ReplaySubject Options:
// Replay last 3 values
new ReplaySubject(3);
// Replay all values ever
new ReplaySubject();
// Replay last 2 values
// OR values from last 500ms
new ReplaySubject(2, 500);
π― Comparing All Subjects
| Type | Remembers | New Subscriber Gets |
|---|---|---|
| Subject | Nothing | Future values only |
| BehaviorSubject | Last value | Current + future |
| ReplaySubject | Last N values | N past + future |
Visual Example:
// Values emitted: A, B, C
// New subscriber joins after C
Subject: gets nothing, waits
BehaviorSubject: gets C, then waits
ReplaySubject(2): gets B, C, then waits
ReplaySubject(3): gets A, B, C, then waits
πͺ The Complete Picture
graph TD subgraph Observables A["Observable<br>Cold by default"] end subgraph Subjects B["Subject<br>Basic multicast"] C["BehaviorSubject<br>Has current value"] D["ReplaySubject<br>Replays history"] end A -->|subscribe| E["Observer"] B -->|subscribe| E C -->|subscribe| E D -->|subscribe| E E -->|next| F["Handle Data"] E -->|error| G["Handle Error"] E -->|complete| H["Cleanup"]
π Quick Reference
Creating Observables:
// From values
of(1, 2, 3)
// From array
from([1, 2, 3])
// Timer (every second)
interval(1000)
// Custom
new Observable(sub => {
sub.next('hello');
sub.complete();
})
Subject Types:
// Basic Subject
new Subject()
// With initial value
new BehaviorSubject(0)
// Replay last 2
new ReplaySubject(2)
Always Clean Up:
const sub = obs$.subscribe(...);
// When done:
sub.unsubscribe();
π You Made It!
You now understand:
- β What RxJS does
- β How Observables work
- β The Observer pattern
- β Why subscriptions matter
- β Hot vs Cold difference
- β Subject, BehaviorSubject, ReplaySubject
Think of data as water flowing through pipes. RxJS gives you the tools to control that flowβwhen to start, when to stop, and how to share it with others.
βRxJS makes async data feel as natural as drinking water!β
