skip to Main Content

I am using signals in Angular 18 for small local states. But I don’t understand why and when I should use them instead of a normal class member. Let’s take a simple toggle:

Example 1

@Component({...})
export class ToggleComponent {
  toggleState: boolean = false;

  toggle() {
    this.toggleState = !this.toggleState;
  }
}

Example 2

@Component({...})
export class ToggleComponent {
  toggleState = signal(false);

  toggle() {
    this.toggleState.set(!this.toggleState());
  }
}

For this example: is there a real difference between those 2 approaches? Why should I use one and not the other? Given for example a parent and a child, and this child has a button which has the job to change the parent state, would be useful to use signal or whatelse?

4

Answers


  1. Imagine you have three components. Let’s say Header, Sidebar and Main content. And an event changes the (Update) value which only affects Main content.

    • Zone.js All three components (Header, Sidebar, Main Content) are checked for changes.
    • Signals Only the Main Content component is checked and updated

    In summary Zone.js which is traditional state management trigger a global change detection cycle, and Signals Only triggers change detection for the specific parts of the template that depend on the signal.

    In your case: The child component can update a signal that the parent component depends on. Only the parts of the parent component that depend on the signal will be updated.

    In traditional approach the child component can emit an event to the parent component, which then updates its state. This will trigger a global change detection cycle

    Login or Signup to reply.
  2. Here is a simple app (stackblitz) to demonstrate why it really matters. Notice ChangeDetectionStrategy.OnPush.

    In 1 second the result is "2 1 1".

    In 2 seconds the result is still "2 1 1".

    In 3 seconds the result is finally "2 2 2".

    import 'zone.js';
    import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    import { timer } from 'rxjs';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      changeDetection: ChangeDetectionStrategy.OnPush,
      template: `
        {{ foo() }}
        {{ bar }}
        {{ baz() }}
      `,
    })
    export class App {
      foo = signal(1);
      bar = 1;
      baz = signal(1);
    
      ngOnInit(): void {
        timer(1000).subscribe(() => this.foo.set(2));
        timer(2000).subscribe(() => (this.bar = 2));
        timer(3000).subscribe(() => this.baz.set(2));
      }
    }
    
    bootstrapApplication(App);
    
    Login or Signup to reply.
  3. As a rule of thumb, signals will mark your component as dirty and schedule change detection.

    Signals should represent states, that when updated, should trigger a change detection cycle.

    Login or Signup to reply.
  4. In short – The purpose of signals is to gradually move into zoneless applications where you do not need automatic change detection and rely on atomic data holders which notify you when they change (signals). When you do not use them, angular uses an automatic change detector which checks for changes for every javascript task that executes. It hurts performance and is also a problematic architecture in general.

    If you want a more in depth explaination, There are now several courses in UDEMY that talk about modern angular development using signals.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search