Tracking Angular web application state with Signals is part of Angular's modern reactive approach — it's super clean, fast, and intuitive. Angular Signals were introduced as a way to make reactivity simpler and more predictable than RxJS alone in certain cases.
🧠 What Are Signals in Angular?
Signals are a way to track
reactive values and automatically update the UI or other logic when
those values change.
They’re similar to BehaviorSubject
or computed properties in other frameworks, but:
- They’re
built into Angular.
- No
need to manually subscribe() and unsubscribe().
- Way
less boilerplate than RxJS for basic state tracking.
🧩 Basic Signal Concepts
- signal()
– creates a reactive value
- computed()
– creates a derived value based on other signals
- effect()
– runs side effects when signal values change
🚀 Example: Managing State with Signals
Let’s say we want to
manage a task list in a service:
import { Injectable,
signal, computed, effect } from '@angular/core';
@Injectable({
providedIn: 'root' })
export class TaskService {
private tasks =
signal<string[]>([]); // ✅ Reactive signal
// Public read-only
signal
readonly tasks$ = computed(() =>
this.tasks());
// Add a task
addTask(task: string) {
this.tasks.update(current =>
[...current, task]);
}
// Remove a task
removeTask(index: number) {
this.tasks.update(current =>
current.filter((_, i) => i !== index));
}
}
Now in a component:
@Component({
selector: 'app-task-list',
standalone: true,
template: `
<ul>
<li *ngFor="let task of
taskService.tasks$()">
{{ task }}
</li>
</ul>
`,
})
export class TaskListComponent {
constructor(public taskService:
TaskService) {}
}
✅
You get reactivity with zero subscriptions
✅
Any changes to tasks will automatically reflect in the template
✅
No need for async pipe, OnPush, or ChangeDetectorRef
🛠 Signal Lifecycle Helpers
effect()
Trigger code when a
signal changes (side effects):
effect(() => {
console.log("Tasks updated:",
this.tasks());
});
computed()
Create a signal that derives
from others:
readonly taskCount =
computed(() => this.tasks().length);
💡 Why Use Signals for State?
Benefits |
Compared
to |
Zero
manual subscriptions |
RxJS |
Automatic
change detection |
ChangeDetectorRef,
OnPush |
Cleaner
syntax |
BehaviorSubject
& .next() |
Faster
and more predictable |
Especially
in component templates |
🧪 When to Use Signals vs RxJS?
Use
Signals When... |
Use
RxJS When... |
Local
or simple global state |
Complex
async flows (HTTP, websockets) |
You
want template reactivity with ease |
You
need stream operators (switchMap, etc.) |
Need
minimal boilerplate |
Need
more stream control |
🧠 Summary
Concept |
Description |
signal() |
Creates
a reactive variable |
computed() |
Creates
a derived value based on signals |
effect() |
Reacts
to signal changes (side effects) |
update() |
Updates
signal values cleanly |
No comments:
Post a Comment