2

I am trying to understand the advantage of using Angular Singnals. There is a count example given in many explanations but what I am trying to understand is the advantage of using signals this way as opposed to the way I have done below via variables myCount and myCountDouble?

https://stackblitz.com/edit/angular-qtd3ku?file=src/main.ts

Here is my code + stackblitz

import 'zone.js/dist/zone';
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { signal } from './signals/signal';
import { computed } from './signals/computed';
import { effect } from './signals/effect';
import { TestArraysCmp } from './testing-arrays.component';
import { TestObjectsCmp } from './testing-objects.component';

/*
  ⚠️ Please keep in mind that this is only the signals implementation. We still depend on zone and current CD strategy to propagate change in the template which might not be the case when Angular releases signals officially!
*/

// Signals are primitives, so we can use them outside the component class
const myValue = signal(10000);

effect(() => {
  console.log('MyValue changed', myValue());
});

// Uncomment this
// setInterval(() => {
//   myValue.update((s) => s - 1);
// }, 1000);

@Component({
  selector: 'my-app',
  standalone: true,
  template: `
    <div>Count: {{ count() }}</div>
    <div>Double: {{ double() }}</div>
    <div>MyCount: {{myCount}}</div>
    <div>MyDoubleCount: {{myCountDouble}}</div>
    <button (click)="inc()">Increase</button>
    <button (click)="reset()">Reset</button>

    <br>
    <!-- <test-arrays /> -->
    <!-- <test-objects /> -->

  `,
  imports: [TestArraysCmp, TestObjectsCmp],
})
export class App {
  myCount: number = 0;
  myCountDouble: number = 0;
  myCountType: string;

  count = signal(0);

  double = computed(() => this.count() * 2);

  countType = computed(() => (this.count() % 2 === 0 ? 'even' : 'odd'));

  constructor() {
    effect(() => {
      console.log('Count changed', this.count());
      console.log(this.count(), 'is', this.countType());
    });
  }

  inc() {
    this.count.update((c) => c + 1);
    this.myCount = this.myCount + 1;
    this.myCountDouble = this.myCount * 2;
    this.myCountType = this.myCount % 2 === 0 ? 'even' : 'odd';
    console.log('Old Way', this.myCount, 'is', this.myCountType);
  }
  reset() {
    this.count.set(0);
    this.myCount = 0;
    this.myCountDouble = 0;
    this.myCountType = '';
  }
}

bootstrapApplication(App);
Ka Tech
  • 8,937
  • 14
  • 53
  • 78

1 Answers1

6

The advantage is mostly related to the way Angular handles change detection.

With Zone.js, when you trigger the inc() method, Angular will look down the entire component tree for changes, even if just that one thing has changed.

With signals, we indicate specifically that only a particular thing has changed and needs to be updated.

As updating a counter is a synchronous operation - we don't need to wait for an API response, we know the value, and therefore we can use it to update the counter right away - using a signal will perform better as it indicates to Angular exactly that only the elements that depend of that signal should be updated thus eliminating the need for dirty checking the entire component tree.

licvdom
  • 76
  • 5
  • Thanks this make a bit more sense. Is this what React does with its change detection? I assume this means smoother peformance for complex UIs? – Ka Tech Mar 07 '23 at 02:16
  • 2
    React uses a Virtual DOM to mimic the real DOM. From there, it takes snapshots of the DOM based on the state, and through comparison (or reconciliation) of those snapshots, it will then decide which parts need to be updated (in the real DOM). It seems more like signals, as a Reactive Primitive, will bring to Angular the Reactive Paradigm we can find in Solidjs - by updating only the parts of the DOM that are directly tied to a specific data change – licvdom Mar 07 '23 at 18:50
  • In v16 signals are still hooked to Zone.js. This isn't true ATM, but will be in the end. – Matthieu Riegler May 21 '23 at 13:07
  • @MatthieuRiegler do you have the source of your comment? I am setting up an application with `zone noop` and signals which works, I would like to understand in deep how signals are still hooked to zonejs – xavadu Jun 13 '23 at 11:52
  • You won't have change detection running automaticaly when using `{ provide: NgZone, useClass: ɵNoopNgZone}`. See https://stackblitz.com/edit/angular-e6kcic?file=src%2Fmain.ts – Matthieu Riegler Jun 13 '23 at 13:57