Bird
Raised Fist0
Angularframework~8 mins

BehaviorSubject as simple store in Angular - Performance & Optimization

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Performance: BehaviorSubject as simple store
MEDIUM IMPACT
This affects interaction responsiveness and rendering updates by controlling how often Angular components re-render based on store changes.
Managing shared state updates in Angular components
Angular
import { BehaviorSubject } from 'rxjs';
import { distinctUntilChanged, map } from 'rxjs/operators';

const store = new BehaviorSubject({ count: 0 });

// In component
store.pipe(
  map(state => state.count),
  distinctUntilChanged()
).subscribe(count => {
  this.count = count;
});

// Updating store frequently
store.next({ count: Math.random() });
Filtering with distinctUntilChanged prevents re-renders when the count value hasn't changed, reducing unnecessary Angular change detection cycles.
📈 Performance GainReduces re-renders and change detection runs, improving INP and overall responsiveness.
Managing shared state updates in Angular components
Angular
import { BehaviorSubject } from 'rxjs';

const store = new BehaviorSubject({ count: 0 });

// In component
store.subscribe(value => {
  // Directly update component state on every emission
  this.count = value.count;
  // No filtering or distinct checks
});

// Updating store frequently
store.next({ count: Math.random() });
Subscribing without filtering causes Angular to re-render components on every store emission, even if data hasn't meaningfully changed.
📉 Performance CostTriggers multiple unnecessary change detections and re-renders, increasing INP latency.
Performance Comparison
PatternDOM OperationsReflowsPaint CostVerdict
BehaviorSubject without filteringMany updates to component stateMultiple reflows due to frequent DOM updatesHigh paint cost from unnecessary renders[X] Bad
BehaviorSubject with distinctUntilChangedUpdates only on meaningful state changesSingle or minimal reflowsLower paint cost due to fewer renders[OK] Good
Rendering Pipeline
BehaviorSubject emits new values which trigger Angular's change detection. If the emitted value changes, Angular updates the DOM accordingly.
Change Detection
Render
Composite
⚠️ BottleneckChange Detection stage is most expensive when many unnecessary updates occur.
Core Web Vital Affected
INP
This affects interaction responsiveness and rendering updates by controlling how often Angular components re-render based on store changes.
Optimization Tips
1Filter BehaviorSubject emissions to avoid unnecessary Angular change detection.
2Use distinctUntilChanged to emit only meaningful state changes.
3Minimize frequent store updates that cause multiple re-renders.
Performance Quiz - 3 Questions
Test your performance knowledge
What is the main performance risk when using BehaviorSubject as a simple store without filtering emissions?
AIncreased bundle size due to BehaviorSubject
BUnnecessary Angular change detection and re-renders
CSlower initial page load (LCP)
DHigher network latency
DevTools: Performance
How to check: Record a performance profile while interacting with the app. Look for frequent change detection cycles and re-renders triggered by BehaviorSubject emissions.
What to look for: High number of change detection events and long scripting times indicate inefficient store updates.

Practice

(1/5)
1. What is the main purpose of using BehaviorSubject in Angular as a simple store?
easy
A. To hold and share the latest value with all subscribers immediately
B. To perform HTTP requests automatically
C. To create Angular components dynamically
D. To manage routing between pages

Solution

  1. Step 1: Understand BehaviorSubject role

    BehaviorSubject holds a current value and shares it with subscribers immediately when they subscribe.
  2. Step 2: Compare with other options

    The other options describe unrelated Angular features like HTTP, components, and routing.
  3. Final Answer:

    To hold and share the latest value with all subscribers immediately -> Option A
  4. Quick Check:

    BehaviorSubject shares latest value immediately [OK]
Hint: BehaviorSubject always gives current value to new subscribers [OK]
Common Mistakes:
  • Confusing BehaviorSubject with HTTP or routing
  • Thinking it delays value delivery
  • Assuming it creates components
2. Which of the following is the correct way to update the value stored in a BehaviorSubject named store$?
easy
A. store$.update(newValue);
B. store$.next(newValue);
C. store$.setValue(newValue);
D. store$.emit(newValue);

Solution

  1. Step 1: Recall BehaviorSubject update method

    The method to update a BehaviorSubject's value is next().
  2. Step 2: Check other method names

    Methods like update(), setValue(), and emit() do not exist on BehaviorSubject.
  3. Final Answer:

    store$.next(newValue); -> Option B
  4. Quick Check:

    Use next() to update BehaviorSubject [OK]
Hint: Use next() to push new values to BehaviorSubject [OK]
Common Mistakes:
  • Using update() or setValue() instead of next()
  • Confusing EventEmitter with BehaviorSubject
  • Trying to assign value directly
3. Given this Angular code snippet, what will be logged to the console?
const store$ = new BehaviorSubject(0);
store$.subscribe(value => console.log('Subscriber 1:', value));
store$.next(5);
store$.subscribe(value => console.log('Subscriber 2:', value));
store$.next(10);
medium
A. Subscriber 1: 0 Subscriber 2: 0 Subscriber 1: 5 Subscriber 2: 5 Subscriber 1: 10 Subscriber 2: 10
B. Subscriber 1: 0 Subscriber 1: 5 Subscriber 2: 0 Subscriber 1: 10 Subscriber 2: 10
C. Subscriber 1: 0 Subscriber 1: 5 Subscriber 2: 5 Subscriber 1: 10 Subscriber 2: 10
D. Subscriber 1: 5 Subscriber 2: 5 Subscriber 1: 10 Subscriber 2: 10

Solution

  1. Step 1: Trace first subscription

    Subscriber 1 subscribes first and immediately receives initial value 0, then receives 5 after next(5).
  2. Step 2: Trace second subscription

    Subscriber 2 subscribes after next(5), so it immediately receives current value 5.
  3. Step 3: Trace next(10) call

    Both subscribers receive 10 after next(10).
  4. Final Answer:

    Subscriber 1: 0 Subscriber 1: 5 Subscriber 2: 5 Subscriber 1: 10 Subscriber 2: 10 -> Option C
  5. Quick Check:

    BehaviorSubject sends current value on subscribe [OK]
Hint: New subscribers get latest value immediately [OK]
Common Mistakes:
  • Assuming second subscriber gets initial 0 instead of 5
  • Missing initial value emission on subscribe
  • Confusing order of console logs
4. Identify the error in this Angular code using BehaviorSubject as a simple store:
const store$ = new BehaviorSubject();
store$.subscribe(value => console.log(value));
store$.next(42);
medium
A. subscribe() must be called with an object, not a function
B. next() cannot be called after subscribe()
C. BehaviorSubject cannot emit numbers
D. BehaviorSubject requires an initial value when created

Solution

  1. Step 1: Check BehaviorSubject constructor

    BehaviorSubject requires an initial value passed to its constructor; here it is missing.
  2. Step 2: Validate other statements

    Calling next() after subscribe() is valid; subscribe() accepts a function; BehaviorSubject can emit numbers.
  3. Final Answer:

    BehaviorSubject requires an initial value when created -> Option D
  4. Quick Check:

    BehaviorSubject must have initial value [OK]
Hint: Always provide initial value to BehaviorSubject constructor [OK]
Common Mistakes:
  • Omitting initial value in constructor
  • Thinking next() can't be called after subscribe()
  • Confusing subscribe() argument types
5. You want to create a simple store using BehaviorSubject to hold a user's profile object and update it safely. Which approach correctly updates only the user's name without losing other profile data?
const profile$ = new BehaviorSubject({ name: 'Alice', age: 30 });
// Update name to 'Bob' here
hard
A. profile$.next({ ...profile$.value, name: 'Bob' });
B. profile$.next({ name: 'Bob' });
C. profile$.value.name = 'Bob';
D. profile$.update({ name: 'Bob' });

Solution

  1. Step 1: Understand BehaviorSubject value update

    Directly assigning to value property does not notify subscribers; next() must be called with full updated object.
  2. Step 2: Preserve existing data while updating name

    Use spread operator to copy existing profile and override name, then call next() with new object.
  3. Step 3: Check other options

    profile$.next({ name: 'Bob' }); loses age property; profile$.value.name = 'Bob'; mutates value without notification; profile$.update({ name: 'Bob' }); uses non-existent update() method.
  4. Final Answer:

    profile$.next({ ...profile$.value, name: 'Bob' }); -> Option A
  5. Quick Check:

    Use next() with spread to update partial data [OK]
Hint: Use spread operator with next() to update partial store data [OK]
Common Mistakes:
  • Overwriting entire object losing other properties
  • Mutating value directly without next()
  • Using non-existent update() method