skills/dev-skills/angular-developer/references/signals-overview.md
Signals are the foundation of reactivity in modern Angular applications. A signal is a wrapper around a value that notifies interested consumers when that value changes.
signal)Use signal() to create state that can be directly updated.
import {signal} from '@angular/core';
// Create a writable signal
const count = signal(0);
// Read the value (always requires calling the getter function)
console.log(count());
// Update the value directly
count.set(3);
// Update based on the previous value
count.update((value) => value + 1);
When exposing state from a service, it is a best practice to expose a readonly version to prevent external mutation.
private readonly _count = signal(0);
// Consumers can read this, but cannot call .set() or .update()
readonly count = this._count.asReadonly();
computed)Use computed() to create read-only signals that derive their value from other signals.
import {signal, computed} from '@angular/core';
const count = signal(0);
const doubleCount = computed(() => count() * 2);
// doubleCount automatically updates when count changes.
A reactive context is a runtime state where Angular monitors signal reads to establish a dependency.
Angular automatically enters a reactive context when evaluating:
computed signalseffect callbackslinkedSignal computationsuntracked)If you need to read a signal inside a reactive context without creating a dependency (so that the context doesn't re-run when the signal changes), use untracked().
import {effect, untracked} from '@angular/core';
effect(() => {
// This effect only runs when currentUser changes.
// It does NOT run when counter changes, even though counter is read here.
console.log(`User: ${currentUser()}, Count: ${untracked(counter)}`);
});
The reactive context is only active for synchronous code. Signal reads after an await will not be tracked. Always read signals before asynchronous boundaries.
// ❌ INCORRECT: theme() is not tracked because it is read after await
effect(async () => {
const data = await fetchUserData();
console.log(theme());
});
// ✅ CORRECT: Read the signal before the await
effect(async () => {
const currentTheme = theme();
const data = await fetchUserData();
console.log(currentTheme);
});