LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 3716 min read

State Management

Share state across unrelated components using a signal-based service, and understand when a dedicated library like NgRx is worth it.

The Simplest Approach: A Shared Service

Because a providedIn: 'root' service is a singleton shared across the whole app, a plain service holding state (backed by signals) is often all a project genuinely needs — no dedicated state library required.

A Signal-Based Store Service

import { Injectable, signal, computed } from '@angular/core';
interface CartItem {
id: number;
name: string;
price: number;
}
@Injectable({ providedIn: 'root' })
export class CartStore {
private items = signal<CartItem[]>([]);
readonly cartItems = this.items.asReadonly();
readonly totalPrice = computed(() =>
this.items().reduce((sum, item) => sum + item.price, 0)
);
addItem(item: CartItem) {
this.items.update(current => [...current, item]);
}
removeItem(id: number) {
this.items.update(current => current.filter(item => item.id !== id));
}
}
// Any component can inject and use it
export class CartSummaryComponent {
private cartStore = inject(CartStore);
items = this.cartStore.cartItems;
total = this.cartStore.totalPrice;
}
asReadonly() Protects the Source of Truth

Exposing cartItems as a read-only signal (rather than the raw, writable items signal) means components can read the cart, but must go through addItem/removeItem to change it — keeping mutations centralized and traceable.

When to Reach for NgRx

NgRx is Angular's most established dedicated state management library, built around the Redux pattern — a single store, dispatched actions, and pure reducer functions. It adds real structure (and real boilerplate) that pays off specifically at a certain scale.

A Shared Signal Service Is Enough When...

  • State is scoped to one feature or a handful of components
  • The update logic is straightforward
  • You want to avoid extra dependencies and boilerplate

Consider NgRx When...

  • State changes need to be traceable/time-travel debuggable across a large app
  • Many independent teams touch the same shared state
  • You need strict, enforced unidirectional data flow at scale

FAQs

No — many production Angular apps use nothing more than well-organized, signal-based services, reserving NgRx for genuinely large, complex state graphs.

Yes — NgRx has increasingly embraced signals (via NgRx SignalStore), narrowing the gap between a lightweight service-based approach and a full dedicated store.

Summary

A signal-based service covers the vast majority of Angular state-sharing needs, with NgRx available for the specific cases where its added structure genuinely pays off. With forms, modules, and state covered, the next section moves into advanced customization — starting with your own directives and pipes.

Next Lesson →

Custom Directives & Pipes