π 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
,ReplaySubject
does 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
null
output).
π 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
scan
in 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)