ReviseAlgo Logo

RxJS

BehaviorSubject

Master RxJS BehaviorSubjects, covering state caching, state management patterns, and synchronous value access.

Last Updated: July 15, 2026 12 min read

1. Learning Objectives

In this lesson, you will master the BehaviorSubject, the primary tool for reactive state management in Angular services. By the end of this topic, you will be able to:

  • Explain the difference between a plain Subject and a BehaviorSubject.
  • Initialize a BehaviorSubject with a default state value.
  • Describe how BehaviorSubject handles late subscribers by emitting the current value immediately.
  • Synchronously retrieve the current state using the .getValue() method.
  • Build a reactive service that exposes readonly state while modifying it via private subjects.

2. Overview

A BehaviorSubject is a specialized type of Subject that represents a value that changes over time. It has two unique features: it requires an **initial value** upon creation, and it **caches the last emitted value**. When a new observer subscribes, it immediately receives the current cached value, even if they subscribed long after the value was emitted. It also allows synchronous reads of the current state via .getValue().

3. Why This Topic Matters

BehaviorSubject is the backbone of local state management in Angular applications:

  • State Synchronization: If you have an authenticated user profile, a shopping cart, or a dark mode toggle, multiple parts of your UI must know the current state *immediately* upon mounting. A BehaviorSubject ensures components don't start with blank templates or load stale default states.
  • Synchronous Checks: Sometimes you need to know the state right now without setting up an asynchronous callback (e.g., checking if a user is logged in inside a route guard). BehaviorSubject.getValue() lets you read state instantly.

4. Real-World Analogy

Think of a BehaviorSubject like a **Digital Thermostat on the wall**:

  • Initial State: The thermostat is never blank; when it turns on, it immediately measures and displays a starting temperature (e.g. 72°F).
  • Cached Value: It continuously holds the current room temperature.
  • Immediate Delivery: If you walk up to the thermostat and look at it (subscribing), you don't have to wait for the heater to cycle or wait for the temperature to change. It immediately tells you the current temperature (72°F) the instant you look at it.

5. Core Concepts

Below is a comparison of how Subjects and BehaviorSubjects manage data delivery:

Feature Subject BehaviorSubject
Initial Value No starting value required. Mandatory initial value upon construction.
Late Subscriber Emits Nothing (misses past events). Emits the current cached value immediately.
Synchronous Read No. Cannot read current value directly. Yes. Via `.getValue()` or `.value`.

6. Syntax & API Reference

This is the syntax for managing state with BehaviorSubject:

7. Visual Diagram

This timeline displays value caching and immediate emission to late subscribers:

8. Live Example — Full Working Code

Below is a complete theme-switching service that stores user preferences reactively, updating styling in independent components:

What just happened? The ThemeService starts with a value of `'light'`. When ThemeContainerComponent mounts and subscribes to theme$, it immediately receives `'light'` and sets its background. Clicking the button calls toggleTheme(), pushing `'dark'` into the stream. Both components receive the notification and redraw.

9. Interactive Playground

Try It Yourself Challenges:

  1. Modify ThemeService to load the initial theme string dynamically from browser localStorage if available, falling back to 'light'.
  2. Add a new component that does not subscribe to theme$ but uses themeService.getCurrentTheme() in a method to show how it extracts state synchronously.

10. Common Mistakes

Mistake Why it happens Wrong Correct
Mutating Arrays/Objects in State Pushing elements directly onto a state array does not update the reference, so change detection ignores it. const cur = bs.value;
cur.push(item);
bs.next(cur);
const cur = bs.value;
bs.next([...cur, item]);
Failing to Provide Initial Value Instantiating a BehaviorSubject without providing a default value results in compiler errors. new BehaviorSubject<string>() new BehaviorSubject<string>('init')

11. Best Practices

  • Enforce Immutability: Always push new object references (via array spreading or cloning) into .next() to avoid silent data mutations.
  • Keep Subjects Private: Never expose BehaviorSubject directly. Expose it via asObservable() to ensure write permissions are restricted.
  • Avoid Over-using getValue(): Rely primarily on stream subscriptions rather than reading values synchronously with .getValue() to maintain reactive data flows.

12. Browser Compatibility/Requirements

BehaviorSubjects are plain JavaScript classes and perform consistently in all modern web browsers.

13. Interview Questions

Q1: How does BehaviorSubject handle a new subscriber differently than a standard Subject?

Answer: A standard Subject does not cache values; it only emits values to observers currently subscribed when next() is called. A BehaviorSubject caches the last emitted value and emits it immediately to any new observer upon subscription.

Q2: Why is it recommended to use spread operators when updating state stored in a BehaviorSubject?

Answer: Direct mutation (e.g., arr.push()) alters data in place without changing the array reference. Angular change detection relies on object reference changes. Creating a new array reference (e.g., [...arr, item]) guarantees change detection picks up the update.

14. Debugging Exercise

Identify why the UI does not refresh when adding items to this list store:

View Solution

Diagnosis: The list reference retrieved by itemsSubject.getValue() is mutated in place using list.push(item). Passing the mutated reference to .next() emits the exact same array reference. Angular components bound via the async pipe won't detect the change.

Fix: Create a new array instance using the ES6 spread operator to trigger a reference change.

15. Practice Exercises

Exercise 1: Implement an authentication state store

Build an AuthService containing user profiles and authentication status using a BehaviorSubject. Add login() and logout() methods. Build an Angular Route Guard that uses .getValue() to inspect authentication status synchronously during transitions.

16. Scenario-Based Challenge

The Multi-Step Checkout Form Store:

You are implementing a 3-step wizard checkout flow. Create a CheckoutFormStoreService that uses a BehaviorSubject to maintain progressive form inputs (shipping details, payment methods, confirmation). Design the service to ensure components can subscribe to read active progress at any step and load filled data if navigating backwards.

17. Quick Quiz

Q1: What are the two main characteristics of a BehaviorSubject?

A) No default value required; discards all past events

B) Requires initial value; caches and emits the last value to late subscribers

C) Non-cancellable; only processes single emissions

Answer: B — BehaviorSubjects require an initial value and cache emissions to play them to late subscribers.

18. Summary & Key Takeaways

  • BehaviorSubjects represent states with historical cache and default values.
  • New observers get the last emitted value immediately on subscription.
  • You can synchronously inspect the active state with the .getValue() method.
  • Exposing private BehaviorSubjects as read-only observables ensures correct architecture.

19. Cheat Sheet

API / Method Purpose
new BehaviorSubject(val) Creates a BehaviorSubject with the specified initial value.
subject.getValue() Synchronously retrieves the current state value.
subject.next(newVal) Updates the cached state and broadcasts it to all subscribers.
---