Dec 10, 2025

Angular Signals Part 1: The New Reactive Heart of Angular

Tags

When I first heard about Angular Signals, I was intrigued. Angular has relied on Zone.js and RxJS for reactive change detection and state management for years. But those systems, while powerful, come with their downsides. Signals promise to change the game, offering a fresh, more efficient way to handle reactivity directly inside Angular’s core.


angular-signal-reactive-heart-of-application

What Are Angular Signals and Why Now?


Signals are reactive primitives introduced to solve some limitations in Angular’s change detection model—particularly those related to Zone.js. Historically, Angular used Zone.js to detect when to update the DOM. While effective, Zone.js can lead to performance bottlenecks because it triggers change detection broadly, even if only a small part of your app truly needs updating.


Signals bring fine-grained, explicit reactivity. They track dependencies at a micro-level and notify Angular precisely when and where updates are needed, skipping unnecessary DOM work. This makes apps faster and more predictable.


Signals vs RxJS and Other Reactive Systems


You might wonder: "But what about RxJS and Observables, which Angular developers already love?" Signals differ fundamentally:


  • RxJS implements a push-based model, ideal for modeling async data streams like HTTP requests or user events.
  • Signals follow a pull-based model, focusing on tracking dependencies and memoizing derived data in synchronous state management.

Signals aren’t a replacement for RxJS everywhere, but complement it by handling local UI state and immediate reactive dependencies more naturally and efficiently.


Diving Into Core Signal Primitives with Small Examples


Let’s explore Angular’s core signal APIs with simple examples.


signal(): Creating and Reading Signals


Signals hold reactive values you can read and update.


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

const count = signal(0);

console.log(count()); // Reading signal value, outputs: 0


Signals can hold primitives like numbers or complex objects.


const user = signal({ name: 'Alice', age: 30 });
console.log(user().name); // "Alice"


set(), update(), mutate(): Modifying Signals


  • set(newValue) replaces the signal value entirely.
  • update(fn) updates the signal based on the previous value.
  • mutate(fn) is for quick, direct mutations on object signals.

Example:


count.set(5); // sets to 5
count.update(c => c + 1); // increments count to 6

user.mutate(u => u.age++); // increments age to 31


Use set when replacing the whole value, update for calculated updates, and mutate for in-place object changes.


computed(): Derived/Readonly Signals


Computed signals derive values automatically from other signals and memoize results—running computations only when dependencies change.


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

const doubleCount = computed(() => count() * 2);
console.log(doubleCount()); // 12 (since count is 6)


effect(): Side Effects on Signal Changes


Effects run code in response to signal changes—perfect for syncing state or triggering DOM updates.


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

effect(() => {
  console.log(`Count changed: ${count()}`);
});


Important: avoid placing business logic inside effects—keep them focused on side-effects like logging or API calls.


This is just the beginning! In Part 2, we'll explore how to use signals within components and templates for blazing-fast UI updates without Zone.js overhead.


EmoticonEmoticon