Skip to content

What is Subject ​

📘 RxJS Official: Subject

Subject is a special kind of Observable in RxJS. Whereas a normal Observable provides unidirectional data flow, a Subject is a hybrid entity with both "Observable" and "Observer" properties.

Subject has the following characteristics:

  • Can publish data (Observable function)
  • Can subscribe to data (Observer function)
  • Can deliver the same value to multiple subscribers (Multicast)
  • Receive only values that occur after subscription (Hot Observable feature)

Basic Usage of Subject ​

ts
import { Subject } from 'rxjs';

// Create a Subject
const subject = new Subject<number>();

// Subscribe as an Observer
subject.subscribe(value => console.log('Observer A:', value));
subject.subscribe(value => console.log('Observer B:', value));

// Publish values as an Observable
subject.next(1); // Publish values to both subscribers
subject.next(2); // Publish values to both subscribers

// Add a new subscriber (delayed subscription)
subject.subscribe(value => console.log('Observer C:', value));

subject.next(3); // Publish values to all subscribers

// Notify completion
subject.complete();

Execution Result ​

Observer A: 1
Observer B: 1
Observer A: 2
Observer B: 2
Observer A: 3
Observer B: 3
Observer C: 3

Difference from Normal Observable ​

The Subject is a Hot Observable and differs from a normal Cold Observable in the following ways:

  • Data is issued with or without subscriptions
  • The same value can be shared by multiple subscribers (multicast)
  • Values can be published externally with .next()
  • Past values are not retained, only post-subscription values are received

Subject and Multicasting ​

One of the key features of Subject is "multicasting". This is the ability to efficiently distribute a single data source to multiple subscribers.

ts
import { Subject, interval } from 'rxjs';
import { take } from 'rxjs';

// Data source
const source$ = interval(1000).pipe(take(3));

// Subject for multicasting
const subject = new Subject<number>();

// Connect source to Subject
source$.subscribe(subject); // Subject functions as a subscriber

// Multiple observers subscribe to the Subject
subject.subscribe(value => console.log('Observer 1:', value));
subject.subscribe(value => console.log('Observer 2:', value));

Execution Result ​

Observer 1: 0
Observer 2: 0
Observer 1: 1
Observer 2: 1
Observer 1: 2
Observer 2: 2

This pattern, also called single-source multicast, is used to efficiently distribute a single data source to multiple subscribers.

Two Uses of Subject ​

There are two main uses for Subject. Each has a different use and behavior.

1. Pattern of Calling .next() Yourself ​

The Subject is used as the Observable. This pattern is suitable for "sending explicit values" such as event notifications or status updates.

ts
const subject = new Subject<string>();

subject.subscribe(val => console.log('Observer A:', val));
subject.next('Hello');
subject.next('World');

// Output:
// Observer A: Hello
// Observer A: World

2. Pattern of Relaying Observable (Multicast) ​

The Subject acts as an Observer, receiving values from the Observable and relaying them. This usage is useful for converting a Cold Observable to Hot and multicasting it.

ts
const source$ = interval(1000).pipe(take(3));
const subject = new Subject<number>();

// Observable → Subject (relay)
source$.subscribe(subject);

// Subject → Deliver to multiple subscribers
subject.subscribe(val => console.log('Observer 1:', val));
subject.subscribe(val => console.log('Observer 2:', val));

// Output:
// Observer 1: 0
// Observer 2: 0
// Observer 1: 1
// Observer 2: 1
// Observer 1: 2
// Observer 2: 2

TIP

It is easier to understand if you imagine .next() as "a person who speaks himself" when you call .next() yourself, or as "a person who uses a microphone to amplify another person's speech" when you receive it from an Observable and relay it.

Practical Use Cases for Subject ​

Subject is particularly useful in the following scenarios:

  1. State Management - sharing and updating application state
  2. Event Bus - communication between components
  3. HTTP response sharing - multiple components share the results of the same API call
  4. Centralized UI Event Management - handle various UI operations in one place

Example: Event Bus Implementation ​

ts
import { Subject } from 'rxjs';
import { filter } from 'rxjs';

interface AppEvent {
  type: string;
  payload: any;
}

// Application-wide event bus
const eventBus = new Subject<AppEvent>();

// Subscribe to specific event types
eventBus.pipe(
  filter(event => event.type === 'USER_LOGGED_IN')
).subscribe(event => {
  console.log('User logged in:', event.payload);
});

// Subscribe to another event type
eventBus.pipe(
  filter(event => event.type === 'DATA_UPDATED')
).subscribe(event => {
  console.log('Data updated:', event.payload);
});

// Publish events
eventBus.next({ type: 'USER_LOGGED_IN', payload: { userId: '123', username: 'test_user' } });
eventBus.next({ type: 'DATA_UPDATED', payload: { items: [1, 2, 3] } });

Execution Result ​

User logged in: {userId: '123', username: 'test_user'}
Data updated: {items: Array(3)}

Summary ​

Subject is an important component of the RxJS ecosystem that plays the following roles:

  • Has the characteristics of both an Observer and an Observable
  • Provides a means to convert a cold Observable into a hot one
  • Efficiently delivers the same data stream to multiple subscribers
  • Facilitates communication between components and services
  • Provides a foundation for state management and event processing

Released under the CC-BY-4.0 license.