Introduction to Angular Signals

Angular Signals represent one of the most significant shifts in the Angular ecosystem since its inception. Introduced as a developer preview in Angular 16 and now a stable feature, Signals provide a new way to handle reactivity. They allow Angular to track state changes with fine-grained precision, leading to better performance and a more intuitive developer experience.

What are Angular Signals?

A Signal is a wrapper around a value that can notify interested consumers when that value changes. Signals can contain any value, from simple primitives like numbers and strings to complex data structures like arrays and objects.

Unlike traditional variables, signals are reactive. When a signal's value changes, Angular automatically knows exactly which parts of the UI or which derived calculations need to be updated. This is a departure from the traditional "Zone.js" approach where Angular often checks the entire component tree for changes.

The Three Pillars of Signals

To master Angular Signals, you need to understand three core concepts: Writable Signals, Computed Signals, and Effects.

1. Writable Signals

Writable signals are signals that you can update directly. You create them using the signal() function.

import { signal } from '@angular/core';

// Initializing a signal
const count = signal(0);

// Reading a signal (always call it as a function)
console.log(count()); 

// Updating a signal directly
count.set(5);

// Updating based on the previous value
count.update(value => value + 1);
    

2. Computed Signals

A Computed Signal is a reactive value that is derived from other signals. It is read-only and automatically updates whenever its dependencies change.

import { signal, computed } from '@angular/core';

const price = signal(100);
const quantity = signal(2);

// This signal automatically updates when price or quantity changes
const total = computed(() => price() * quantity());
    

3. Effects

An Effect is an operation that runs whenever one or more signal values change. Effects are useful for side effects like logging, manual DOM manipulation, or calling external APIs.

import { effect } from '@angular/core';

effect(() => {
  console.log(`The current count is: ${count()}`);
});
    

Visualizing the Signal Flow

Understanding how data flows through signals is crucial for building efficient applications. Here is a simplified flow of the signal mechanism:

  • Producer: The Signal holding the source data (e.g., a user input).
  • Dependency Tracking: Angular automatically tracks which signals are read inside a computed or effect block.
  • Consumer: The UI or Effect that reacts when the Producer changes.

Flowchart: [Signal Change] -> [Automatic Dependency Notification] -> [Computed Re-evaluation] -> [UI Update / Effect Execution]

Signals vs. Observables

While RxJS Observables are powerful for asynchronous data streams (like HTTP requests), Signals are designed for synchronous state management. Signals are easier to read and don't require manual unsubscription, making them ideal for managing component state.

Real-World Use Case: Shopping Cart

Imagine a shopping cart where the total price and tax must update whenever an item is added or the quantity changes. Using Signals makes this logic clean and performant.

export class CartComponent {
  items = signal([{ name: 'Laptop', price: 1000 }]);
  taxRate = signal(0.1);

  subtotal = computed(() => this.items().reduce((acc, item) => acc + item.price, 0));
  totalTax = computed(() => this.subtotal() * this.taxRate());
  grandTotal = computed(() => this.subtotal() + this.totalTax());

  addItem() {
    this.items.update(prev => [...prev, { name: 'Mouse', price: 50 }]);
  }
}
    

Common Mistakes to Avoid

  • Forgetting Parentheses: A signal is a getter function. You must call mySignal() to get its value. Writing mySignal without parentheses returns the function itself, not the value.
  • Mutating Objects Directly: Signals rely on immutability or the update method to detect changes. Mutating a property inside an object stored in a signal might not trigger an update.
  • Overusing Effects: Don't use effects to propagate state changes (e.g., setting one signal based on another). Use computed signals for that purpose instead.

Interview Notes

  • Q: What is the main benefit of Signals over Zone.js? A: Signals provide fine-grained reactivity, meaning Angular knows exactly which component or DOM element needs to change, reducing the need for expensive change detection cycles across the entire app.
  • Q: Are Signals replacing RxJS? A: No. Signals are for state management and UI reactivity. RxJS is still the preferred tool for complex asynchronous operations, events, and data streams.
  • Q: Can you update a computed signal? A: No, computed signals are read-only. They only change when their source signals change.

Summary

Angular Signals introduce a more declarative and performant way to manage state. By using signal, computed, and effect, you can build applications that are easier to debug and faster to execute. As you progress through this Angular Masterclass, you will see how signals integrate with components and services to simplify complex logic.

In the next lesson, we will explore Advanced Signal Patterns and how to bridge the gap between Signals and RxJS.