Chapter 12: State Management in Angular 20 (Standalone Components)
Managing state effectively is key for scalable Angular applications. In Angular 20, state management can be handled elegantly with services using RxJS, and enhanced with libraries like NgRx or Angular Signals. This chapter explores core state management techniques suitable for standalone component architecture.
1. Service-Based State Management
The simplest approach to manage state is to create a service that holds and manages shared data. Components inject the service and subscribe to changes.
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class CounterService {
private count = 0;
getCount() {
return this.count;
}
increment() {
this.count++;
}
decrement() {
this.count--;
}
}
However, this method doesn’t notify components of changes automatically, so it’s better to use reactive streams.
2. Using RxJS Subjects for Reactive State
Subject
allows components to subscribe and react to state changes.
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class CounterService {
private count = 0;
private countSubject = new Subject();
count$ = this.countSubject.asObservable();
increment() {
this.count++;
this.countSubject.next(this.count);
}
decrement() {
this.count--;
this.countSubject.next(this.count);
}
}
Components can subscribe to count$
to receive live updates.
3. BehaviorSubject: Storing Current State
BehaviorSubject
holds the current state value and emits it immediately on subscription.
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class CounterService {
private countSubject = new BehaviorSubject(0);
count$ = this.countSubject.asObservable();
increment() {
this.countSubject.next(this.countSubject.value + 1);
}
decrement() {
this.countSubject.next(this.countSubject.value - 1);
}
}
Usage in Component
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CounterService } from './counter.service';
@Component({
standalone: true,
imports: [CommonModule],
selector: 'app-counter',
template: `
Counter: {{ count }}
` }) export class CounterComponent { count = 0; constructor(private counterService: CounterService) { this.counterService.count$.subscribe(value => this.count = value); } increment() { this.counterService.increment(); } decrement() { this.counterService.decrement(); } }
4. Introduction to NgRx
NgRx is a powerful Redux-inspired state management library for Angular. It uses a unidirectional data flow and stores application state in a single immutable store.
Core concepts:
- Store: Single source of truth for app state.
- Actions: Events that describe state changes.
- Reducers: Pure functions to handle actions and update state.
- Effects: Handle side effects like API calls.
NgRx requires some setup but excels in large, complex apps where explicit state control is needed.
5. Angular Signals (Experimental)
Angular Signals provide a reactive primitive for state management with better performance and simpler APIs. Signals represent reactive values that components automatically track and update when changed.
Example usage:
import { Component, signal } from '@angular/core';
@Component({
standalone: true,
selector: 'app-signal-counter',
template: `
Signal Counter: {{ count() }}
` }) export class SignalCounterComponent { count = signal(0); increment() { this.count.set(this.count() + 1); } decrement() { this.count.set(this.count() – 1); } }
6. Summary
- Service-based state is simple but limited without reactivity.
- RxJS Subjects and BehaviorSubjects enable reactive and shared state management.
- NgRx offers scalable state management with a unidirectional data flow.
- Angular Signals provide a promising new reactive primitive for efficient state handling.
Next Chapter Preview
Next up, Chapter 13 covers Angular’s Lifecycle Hooks—how and when to use them for optimized component performance.