π Hey Devs,
Welcome back to another weekly deep dive! π
This time, weβre exploring an incredibly useful and powerful concept in RxJS β the ReplaySubject.
In our previous posts, we covered how to pass values asynchronously using Subject and BehaviorSubject. Today, weβll focus on how ReplaySubject differs and why itβs helpful when you want new subscribers to receive previously emitted values.
π What is a ReplaySubject?
A ReplaySubject is similar to a BehaviorSubject, but with a twist β it can replay multiple previously emitted values to new subscribers, not just the latest one.
β Syntax:
const replaySubject = new ReplaySubject(2);
Here, the 2 represents the buffer size β meaning new subscribers will receive the last 2 emitted values upon subscription.
β οΈ Note: Unlike
BehaviorSubject,ReplaySubjectdoes not require an initial value. If you subscribe before emitting any values, youβll receive nothing.
π§ͺ Example in Angular
Letβs take a look at a working example where we use ReplaySubject in an Angular app.
π§© HTML:
<h3>ReplaySubject</h3>
<div class="text-wrapper">
<div class="text">
<textarea
class="textarea-modern"
[(ngModel)]="replaySubjectText"
name="replaySubject"
id="replaySubject"
></textarea>
<div class="btn-container">
<button class="btn-ghost" (click)="sendReplaySubject()" type="button">Send</button>
<button class="btn-ghost" (click)="addReplaySubject()" type="button">Add</button>
</div>
</div>
<div class="example">
@for (item of replaySubjectArray(); track $index) {
@let data = replayObservable | async;
<div class="card">
<div class="index">{{$index}}</div>
@if (data && data.length > 0) {
@for (item of data; track item; let i = $index) {
<div class="card">
<div class="index">{{i}}</div>
<div class="data">{{item | json}}</div>
</div>
}
} @else {
<div class="data">{{data | json}}</div>
}
</div>
}
</div>
</div>
π§ TypeScript:
import { Component, model, OnInit, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReplaySubject, scan } from 'rxjs';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-rxjs-operator',
imports: [CommonModule, FormsModule],
templateUrl: './rxjs-operator.html',
styleUrl: './rxjs-operator.scss',
})
export class RxjsOperator implements OnInit {
replaySubject = new ReplaySubject<string>(2);
replayObservable = this.replaySubject.asObservable().pipe(
scan((acc: string[], curr: string) => [...acc, curr], [])
);
replaySubjectText = model<string>('');
replaySubjectArray = signal<number[]>([0]);
ngOnInit(): void {}
sendReplaySubject() {
this.replaySubject.next(this.replaySubjectText());
}
addReplaySubject() {
this.replaySubjectArray.update((prev) => [...prev, 1]);
}
}
π§ͺ Use Case Breakdown
π Case 1: Initial Load
When the component loads, the ReplaySubject is subscribed to, but no values have been emitted yet β so the UI displays null or empty output.
πΈ Refer to the screenshot showing the initial state (empty or
nulloutput).
π Case 2: Emitting New Values
When you enter a value in the textarea and click the Send button, that value is emitted via replaySubject.next(). We use the scan operator to accumulate emitted values for display.
π We'll cover
scanin more detail in an upcoming blog post!
π Case 3: New Subscribers, Old Data
After emitting more than two values (our buffer size is 2), clicking the Add button creates a new subscriber. That new subscriber immediately receives the last two emitted values β this is the magic of ReplaySubject.
Any newly emitted values will be received by all active subscribers, just like with a regular Subject.
π Under the Hood
Internally, ReplaySubject is a class that extends Subject. Here's a simplified look at how it's structured:
export class ReplaySubject<T> extends Subject<T> {
constructor(
private _bufferSize = Infinity,
private _windowTime = Infinity,
private _timestampProvider: TimestampProvider = dateTimestampProvider
) {
super();
}
next(value: T): void {
// This method is overridden to buffer the emitted values
// and replay them to new subscribers based on the buffer size
}
}
The key difference lies in the overridden next() method. It stores emitted values in memory and re-emits them to new subscribers β depending on the configured bufferSize and windowTime.
This makes ReplaySubject perfect when you want late subscribers to catch up on a stream's most recent activity, rather than starting fresh.
π Conclusion
That wraps up our deep dive into ReplaySubject!
To summarize:
- It stores and replays multiple past values to new subscribers.
- No need for an initial value.
- Super useful when late subscribers need context.
Next up, weβll explore AsyncSubject and see how it fits into the RxJS family.
π¬ Got questions or use cases you want to share? Drop a comment below! Let's discuss more Angular magic. β¨
βοΈ Author: Vetriselvan
π¨βπ» Frontend Developer | π‘ Code Enthusiast | π Lifelong Learner | βοΈ Tech Blogger | π Freelance Developer



Top comments (0)