Skip to main content
Angular Basics
CHAPTER 18 Beginner

State Management Basics

Updated: May 18, 2026
5 min read

# CHAPTER 18

State Management Basics

1. Chapter Introduction

State is any data your application needs to remember — the current user, a list of products, a shopping cart, or whether a modal is open. As apps grow, "who owns the data and who can change it?" becomes a critical architectural question. Poor state management leads to bugs where two components show conflicting data. This chapter covers scalable state management patterns from simple to advanced.

2. Learning Objectives

  • Understand types of state (local, shared, global).
  • Implement service-based state with BehaviorSubject.
  • Understand the problems NgRx solves.
  • Implement a basic store-like pattern with services.

3. Types of State

text
1234
Local State:    Data relevant only to one component (e.g., isDropdownOpen)
Shared State:   Data shared by 2-3 related components (use a Service)
Global State:   Data used across the entire app (user auth, cart — use NgRx or signal store)
Server State:   Data fetched from and synced with a backend API

4. Component-Level State (Local)

Simple boolean flags or form data that only one component needs:
typescript
123456
export class DropdownComponent {
  isOpen: boolean = false;          // Local state
  selectedOption: string = '';       // Local state

  toggle(): void { this.isOpen = !this.isOpen; }
}

5. Service-Based State with BehaviorSubject

BehaviorSubject is perfect for shared state. Unlike a regular Subject, it always holds the current value and emits it immediately to new subscribers.
cart.service.ts
123456789101112131415161718192021222324252627282930313233
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

export interface CartItem {
  id: number;
  name: string;
  price: number;
  quantity: number;
}

@Injectable({ providedIn: 'root' })
export class CartService {
  // BehaviorSubject holds the current state
  private cartItems = new BehaviorSubject<CartItem[]>([]);

  // Expose as Observable (read-only)
  cartItems$ = this.cartItems.asObservable();

  addToCart(item: CartItem): void {
    const current = this.cartItems.getValue();
    this.cartItems.next([...current, item]);  // Immutable update!
  }

  removeFromCart(id: number): void {
    const updated = this.cartItems.getValue().filter(item => item.id !== id);
    this.cartItems.next(updated);
  }

  getTotal(): number {
    return this.cartItems.getValue()
      .reduce((sum, item) => sum + (item.price * item.quantity), 0);
  }
}
cart-icon.component.ts
1234567891011
export class CartIconComponent implements OnInit {
  itemCount: number = 0;

  constructor(private cartService: CartService) {}

  ngOnInit(): void {
    this.cartService.cartItems$.subscribe(items => {
      this.itemCount = items.length;
    });
  }
}
html
1234
<!-- Use the async pipe for automatic subscription management -->
<div class="cart-icon">
  🛒 {{ (cartService.cartItems$ | async)?.length }} items
</div>

6. Introduction to NgRx

For very large applications with complex state interactions, BehaviorSubject services can become hard to manage. NgRx is Angular's official Redux-style state management library.

NgRx follows a strict unidirectional data flow:

text
1234567
Component dispatches an Action
         ↓
    Reducer updates the State
         ↓
    Selector reads from State
         ↓
    Component re-renders
typescript
123456789101112131415
// Example NgRx action
import { createAction, props } from &#039;@ngrx/store&#039;;

export const addToCart = createAction(
  &#039;[Cart] Add Item&#039;,
  props<{ item: CartItem }>()
);

// Example NgRx reducer
import { createReducer, on } from &#039;@ngrx/store&#039;;

export const cartReducer = createReducer(
  [],
  on(addToCart, (state, { item }) => [...state, item])
);

7. Angular Signals (Modern State Management)

Angular 16+ introduced Signals as a simpler reactive primitive:
typescript
12345678910111213
import { signal, computed } from &#039;@angular/core&#039;;

export class CartComponent {
  cartItems = signal<CartItem[]>([]);

  // Computed signal — automatically recalculates when cartItems changes
  itemCount = computed(() => this.cartItems().length);
  total = computed(() => this.cartItems().reduce((s, i) => s + i.price, 0));

  addItem(item: CartItem): void {
    this.cartItems.update(items => [...items, item]);
  }
}

8. Choosing the Right State Solution

ComplexitySolution
Single componentComponent properties
2-3 related componentsShared Service
Feature-levelService + BehaviorSubject
App-wide complex stateNgRx or Angular Signals

9. Common Mistakes

  • Storing state in multiple places: If both ComponentA and ComponentB keep their own copy of "current user", they will get out of sync. Have one source of truth.
  • Mutating state directly: Always create new references when updating: this.items.next([...current, newItem]). Never current.push(newItem).

10. MCQs with Answers

Question 1

What is "state" in an Angular application?

Question 2

What is the advantage of BehaviorSubject over a regular Subject?

Question 3

What method is used to update a BehaviorSubject's value?

Question 4

What method retrieves a BehaviorSubject's current value without subscribing?

Question 5

What is the unidirectional data flow pattern in NgRx?

Question 6

What Angular 16+ feature provides a simpler alternative to Observables for state management?

Question 7

What is a "single source of truth"?

Question 8

Why should you never directly mutate an array stored in a BehaviorSubject (e.g., using .push())?

Question 9

For a shopping cart feature used across multiple pages, which state solution is most appropriate?

Question 10

What does the async pipe do when used with an Observable in a template?

11. Interview Questions

  • Q: Explain the concept of a "single source of truth." Why is it important?
  • Q: Compare service-based state management with BehaviorSubject vs NgRx. When would you choose each?

12. Summary

State management is what separates junior from senior Angular developers. Starting with simple service-based state using BehaviorSubject handles most applications beautifully. For very complex, enterprise-scale state requirements, NgRx provides a predictable, debuggable, and testable solution.

13. Next Chapter Recommendation

We have been using Observables throughout this course. In Chapter 19: Angular RxJS Basics, we go deep into RxJS — the reactive programming library that powers Angular's HttpClient, Router, and Forms.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·