Logo

dev-resources.site

for different kinds of informations.

Angular Signals: From Zero to Hero

Published at
11/3/2024
Categories
angular
signals
webdev
performance
Author
soumayaerradi
Author
13 person written this
soumayaerradi
open
Angular Signals: From Zero to Hero

Reactive programming has become a central paradigm in modern frontend development, with frameworks like Angular relying heavily on observables, event emitters and state management patterns. But with the introduction of Signals, Angular has unlocked a simpler, more intuitive way to manage local state reactively.
In this article, we’ll take you from the basics to advanced use cases of Signals in Angular, explaining how they work, why they’re different from observables and how you can use them to build high-performance Angular applications.

What are Angular Signals?

Angular Signals are reactive values that update automatically when their dependencies change. Think of them as reactive variables: they’re lightweight, synchronous and easy to work with, making them ideal for managing local component state. Unlike observables, which are typically used to handle streams of asynchronous data, signals are synchronous and work perfectly with Angular’s change detection.

In Angular, a signal represents a value that can change over time, and other signals can depend on it. This creates a natural flow of reactive state management within your application, where updates are propagated automatically.

Example:

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

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

// Update signal value
count.set(1);

// Read the signal value
console.log(count()); // Outputs: 1
Enter fullscreen mode Exit fullscreen mode

How Signals Differ from Observables

Although both observables and signals are reactive programming constructs, they differ significantly in their purpose and behavior.

Feature Signals Observables
Push vs Pull Pull-based (get when needed) Push-based (values are emitted)
Synchronous Synchronous and immediate Can be asynchronous
Subscriptions Not required Required
Use Case Local state Streams, async operations

While observables are ideal for streams of events (e.g., HTTP requests, WebSocket messages), signals shine when dealing with local, synchronous state that needs to be accessed and updated within your Angular components.

Setting Up Signals in Angular

To start using signals in Angular, make sure you are working with Angular 16 or above, as this is when they became fully integrated into Angular Core. Below is a basic example of how to use signals in an Angular component:

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

@Component({
  selector: 'app-counter',
  template: `
    <button (click)="increment()">Increment</button>
    <p>Count: {{ count() }}</p>
  `
})
export class CounterComponent {
  count = signal(0);

  increment() {
    this.count.set(this.count() + 1);
  }
}
Enter fullscreen mode Exit fullscreen mode

Advanced Concepts: Derived and Computed Signals

Angular allows you to create derived signals (signals that depend on other signals) which automatically update when their dependencies change. This makes it easy to handle complex state dependencies.

Derived Signals

Derived signals are perfect for managing calculated values that depend on other signals.
Here’s a simple example of creating a derived signal:

const baseCount = signal(10);
const doubleCount = computed(() => baseCount() * 2);

console.log(doubleCount()); // Outputs: 20
Enter fullscreen mode Exit fullscreen mode

In this example, doubleCount will always return twice the value of baseCount. If baseCount changes, doubleCount will update automatically.

Computed Signals

You can also create computed signals, which act similarly to derived signals but are used when you need to perform more complex calculations.

const a = signal(5);
const b = signal(3);
const sum = computed(() => a() + b());

console.log(sum()); // Outputs: 8
Enter fullscreen mode Exit fullscreen mode

Whenever a or b changes, the sum signal will recalculate automatically.

Integrating Signals with Angular Change Detection

One of the key advantages of signals is their deep integration with Angular’s change detection mechanism. Signals trigger updates to the view automatically, even when using OnPush change detection. This significantly improves performance without the need for manual change detection calls.

Example with OnPush:

@Component({
  selector: 'app-signal-example',
  template: `<p>{{ fullName() }}</p>`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class SignalExampleComponent {
  firstName = signal('Soumaya');
  lastName = signal('Erradi');
  fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
}
Enter fullscreen mode Exit fullscreen mode

Even with OnPush, the view will update whenever firstName or lastName changes because of the reactive nature of signals.

Signals in Complex Applications

For more complex scenarios, such as managing the state of an entire application, signals can simplify state management by providing clear and declarative dependencies between different parts of the state. For instance, in a shopping cart application, you can use signals to manage cart items and automatically calculate the total price based on the items added.

Example: Shopping Cart with Signals

@Injectable({ providedIn: 'root' })
export class CartService {
  private items = signal<CartItem[]>([]);

  addItem(item: CartItem) {
    this.items.set([...this.items(), item]);
  }

  getTotalPrice = computed(() =>
    this.items().reduce((total, item) => total + item.price, 0)
  );
}
Enter fullscreen mode Exit fullscreen mode

The getTotalPrice signal will automatically update whenever items are added to or removed from the cart.

Best Practices for Signals

When using signals in Angular applications, follow these best practices for optimal performance and maintainability:

  • Use signals for local, synchronous state: Signals are ideal for managing component state or any synchronous data dependencies within a component.
  • Keep derived signals simple: While derived signals are useful, keep your dependencies minimal to avoid overly complex signal chains that are difficult to debug.
  • Leverage automatic updates: Don’t overcomplicate your signal-based components by manually tracking state updates. Let Angular handle it for you.
  • Combine Signals and Observables: In some cases, you might still need observables for managing asynchronous data. In such cases, use signals for synchronous state and observables for streams.

Conclusion

Angular Signals introduce a fresh approach to managing reactive state in Angular applications. They offer a lightweight, synchronous and declarative way to manage state, making your applications easier to reason about and maintain. As you build out more complex applications, signals can reduce the need for boilerplate code, eliminate the need for manual subscriptions and streamline your change detection.

With this foundational knowledge, you're ready to start building more reactive and performant Angular applications using signals.

Happy coding!

signals Article's
30 articles in total
Favicon
New in Angular: Bridging RxJS and Signals with toSignal!
Favicon
A Complete Solution for Receiving Signals with Built-in Http Service in Strategy
Favicon
Vanilla JS Signal implementation
Favicon
How I'm Using Signals to Make My React App Simpler
Favicon
Angular Migrating to Signals: A Paradigm Shift in Change Detection
Favicon
The Problems with Signals: A Tale of Power and Responsibility
Favicon
Angular Signals: From Zero to Hero
Favicon
Mutable Derivations in Reactivity
Favicon
Introducing Brisa: Full-stack Web Platform Framework 🔥
Favicon
Async Derivations in Reactivity
Favicon
Scheduling Derivations in Reactivity
Favicon
Exploring Angular's Change Detection: In-Depth Analysis
Favicon
Understanding Reactive Contexts in Angular 18
Favicon
New Free eBook: Angular Mastery: From Principles To Practice.
Favicon
What's new in Angular 18
Favicon
Using @HostBinding with Signals
Favicon
Angular Inputs and Single Source of Truth
Favicon
Angular Signal Queries with the viewChild() and contentChild() Functions
Favicon
Converting Observables to Signals in Angular
Favicon
Angular Signals: Best Practices
Favicon
Streamlining Communication: New Signals API in Angular 17.3
Favicon
Signal-Based Inputs and the Output Function
Favicon
What's new in Angular 17.3
Favicon
Master Angular 17.1 and 17.2
Favicon
Angular Computed Signal with an Observable
Favicon
Django Signals mastery
Favicon
How to mock NgRx Signal Stores for unit tests and Storybook Play interaction tests (both manually and automatically)
Favicon
Derivations in Reactivity
Favicon
Improve data service connectivity in Signal Stores using the withDataService Custom Store Feature
Favicon
How Signals Can Boost Your Angular Performance

Featured ones: