Angular 19 introduces an exciting reactive primitive called signals, offering developers a simple yet powerful way to manage local state and derived values without the boilerplate of external libraries. In this blog post, we’ll explore:
- What signals are in Angular 19
- A detailed, working example of signals
- Use cases for signals in real-world apps
- Differences between signals and NgRx Store
Table of Contents
What Are Signals?
A signal is a reactive primitive for storing and tracking state in Angular 19. Under the hood, signals notify subscribers whenever their value changes, enabling automatic updates in templates and computations.
- Declaration: import from
@angular/core
- 245Functions:
signal<T>(initial: T)
: Creates a writable signalcomputed<T>(fn: () => T)
: Derives a signal from other signalseffect(fn: () => void)
: Reacts to changes without returning a value
import { signal, computed, effect } from '@angular/core'; // A simple writable signal const count = signal(0); // A derived signal const doubleCount = computed(() => count() * 2); // Run an effect when `count` changes effect(() => { console.log(`Count changed to ${count()}`); });
How It Works:
- Read a signal’s value by calling it:
count()
- Write by invoking its setter:
count.set(newValue)
, or viacount.update(x => ...)
. - Subscriptions:
computed
andeffect
track dependencies and re-run when inputs change.
Detailed Working Example: Counter Component
Let’s build a reusable counter using Angular 19 signals.
// counter.component.ts import { Component, signal, computed } from '@angular/core'; @Component({ selector: 'app-counter', template: ` <div class="counter"> <h2>Counter: {{ count() }}</h2> <button (click)="increment()">Increment</button> <button (click)="decrement()">Decrement</button> <p>Double: {{ double() }}</p> </div> `, styles: [`.counter { text-align: center; } button { margin: 0 8px; }`] }) export class CounterComponent { // 1. Create a writable signal count = signal(0); // 2. Create a derived signal double = computed(() => this.count() * 2); // 3. Methods to update increment() { this.count.update(n => n + 1); } decrement() { this.count.update(n => n - 1); } }
Explanation:
- count holds the current value.
- double automatically recomputes when count changes.
- Calling
this.count()
in template triggers change detection.
Use Cases for Signals
- Local Component State: Manage form inputs, toggles, and counters without services.
- Derived State: Compute totals, filters, or transforms via
computed
. - Side Effects: Run business logic when state changes using
effect
. - Lightweight Stores: Create scoped stores per feature module instead of a global store.
Pro Tip: Combine signals with Angular’s Dependency Injection to provide feature-level state containers.
Signals vs NgRx Store
Feature | Signals | NgRx Store |
---|---|---|
Boilerplate | Minimal; no actions or reducers | Requires actions, reducers, effects, selectors |
Scope | Local or feature-level | Global or large-scale apps |
API Surface | Signal ,computed , effect |
createEffect , createAction , createReducer , etc. |
Learning Curve | Low; JavaScript API | Higher; Flux architecture |
Debug Tools | Basic logging via effects | Redux DevTools, time-travel debugging |
Use Cases | Simple, reactive state & derived values | Complex state flows, undo-redo, advanced debugging |
When to Choose What?
- Use signals for local state, quick prototypes, and smaller feature modules.
- Opt for NgRx Store in large enterprise apps needing advanced tooling, middleware, and global consistency.
Conclusion
Angular 19 signals offer a declarative, lightweight, and expressive approach to reactive state in Angular applications. Whether you need simple component state or derived data flows, signals can simplify your code and improve performance. For global, complex state management with robust tooling, NgRx Store remains invaluable—but now you have an elegant, built-in alternative for many scenarios. Please feel free to add comments if any queries or suggestions.
Keep learning & stay safe 😉
You may like:
Testing and Debugging Angular 19 Apps
Performance Optimization and Best Practices in Angular 19
If you like our content, please consider buying us a coffee.
Thank you for your support!
Buy Me a Coffee