Bird
Raised Fist0
Angularframework~8 mins

Signals as modern state primitive in Angular - Performance & Optimization

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Performance: Signals as modern state primitive
HIGH IMPACT
Signals impact how Angular tracks and updates UI state, affecting rendering speed and interaction responsiveness.
Managing component state with reactive updates
Angular
import { Component, signal } from '@angular/core';
@Component({ selector: 'app-counter', template: `<button (click)="increment()">Increment</button><p>{{count()}}</p>` })
export class CounterComponent {
  count = signal(0);
  increment() {
    this.count.update(c => c + 1);
  }
}
Signals track dependencies precisely, so only the parts using the signal re-render, reducing change detection scope.
📈 Performance Gainsingle targeted update, avoids full component re-render, improves INP by reducing work on interaction
Managing component state with reactive updates
Angular
import { Component } from '@angular/core';
@Component({ selector: 'app-counter', template: `<button (click)="increment()">Increment</button><p>{{count}}</p>` })
export class CounterComponent {
  count = 0;
  increment() {
    this.count++;
  }
}
Using a simple property for state causes Angular to run change detection on the entire component on each update.
📉 Performance Costtriggers full component re-render and multiple change detection cycles per update
Performance Comparison
PatternDOM OperationsReflowsPaint CostVerdict
Traditional property stateFull component subtree checkedMultiple reflows if DOM changesHigher paint cost due to broad updates[X] Bad
Signal-based stateOnly signal consumers updatedMinimal reflows limited to changed nodesLower paint cost due to targeted updates[OK] Good
Rendering Pipeline
Signals notify Angular's reactive system about state changes, triggering updates only where signals are read, minimizing layout recalculations and paints.
Change Detection
Layout
Paint
⚠️ BottleneckChange Detection stage when using traditional state causes unnecessary checks
Core Web Vital Affected
INP
Signals impact how Angular tracks and updates UI state, affecting rendering speed and interaction responsiveness.
Optimization Tips
1Use signals to track state changes precisely and avoid broad change detection.
2Avoid updating traditional properties that trigger full component re-renders.
3Signals improve interaction responsiveness by minimizing DOM updates.
Performance Quiz - 3 Questions
Test your performance knowledge
How do signals improve Angular's rendering performance compared to traditional state properties?
ABy limiting updates only to components that read the signal
BBy forcing full component re-render on every state change
CBy disabling change detection entirely
DBy batching all DOM updates into one large repaint
DevTools: Performance
How to check: Record a performance profile while interacting with the component; look for change detection and layout events.
What to look for: Reduced time spent in change detection and fewer layout recalculations indicate good signal usage.

Practice

(1/5)
1. What is the main purpose of using signal() in Angular?
easy
A. To style elements dynamically
B. To create a reactive state value that updates the UI automatically
C. To handle HTTP requests
D. To define a new component

Solution

  1. Step 1: Understand the role of signal()

    signal() creates a reactive value that Angular tracks for changes.
  2. Step 2: Connect signal() to UI updates

    When the signal value changes, Angular automatically updates the UI where it is used.
  3. Final Answer:

    To create a reactive state value that updates the UI automatically -> Option B
  4. Quick Check:

    signal() creates reactive state [OK]
Hint: Signals hold reactive values that auto-update UI [OK]
Common Mistakes:
  • Confusing signals with components
  • Thinking signals handle HTTP
  • Assuming signals are for styling
2. Which of the following is the correct way to create a signal with initial value 10 in Angular?
easy
A. const count = signal(10);
B. const count = new Signal(10);
C. const count = createSignal(10);
D. const count = signal.set(10);

Solution

  1. Step 1: Recall the syntax for creating signals

    Angular uses signal(initialValue) to create a signal with a starting value.
  2. Step 2: Check each option's syntax

    Only const count = signal(10); matches the correct syntax. Others use incorrect constructors or methods.
  3. Final Answer:

    const count = signal(10); -> Option A
  4. Quick Check:

    signal() creates with initial value [OK]
Hint: Use signal(value) to create signals [OK]
Common Mistakes:
  • Using new keyword with signal
  • Calling non-existent createSignal function
  • Trying to set value during creation
3. Given the code:
const count = signal(0);
count.set(5);
console.log(count());

What will be printed in the console?
medium
A. 5
B. 0
C. undefined
D. Error: count is not a function

Solution

  1. Step 1: Understand signal creation and update

    The signal count starts at 0, then set(5) changes its value to 5.
  2. Step 2: Reading the signal value

    Calling count() returns the current value, which is 5 after the update.
  3. Final Answer:

    5 -> Option A
  4. Quick Check:

    count.set(5) updates value, count() reads it [OK]
Hint: Use count() to read updated signal value [OK]
Common Mistakes:
  • Thinking count() returns initial value
  • Confusing set() with reading value
  • Assuming count is not callable
4. Identify the error in this Angular signal code:
const name = signal('Alice');
name.update(name + ' Smith');
medium
A. Incorrect initial value type for signal
B. Missing parentheses when calling signal()
C. Using update() with a string instead of a function
D. Using set() instead of update()

Solution

  1. Step 1: Understand update() usage

    update() expects a function that receives the current value and returns the new value.
  2. Step 2: Analyze the code's argument to update()

    The code passes name + ' Smith' which is a string, not a function, causing an error.
  3. Final Answer:

    Using update() with a string instead of a function -> Option C
  4. Quick Check:

    update() needs a function argument [OK]
Hint: Pass a function to update(), not a direct value [OK]
Common Mistakes:
  • Passing value directly to update()
  • Confusing set() and update() usage
  • Ignoring function argument requirement
5. You want to create a signal that holds a list of numbers and add a new number to it reactively. Which code correctly updates the signal to add number 7?
hard
A. numbers.push(7);
B. numbers.set(numbers() + 7);
C. numbers = signal([...numbers(), 7]);
D. numbers.update(list => [...list, 7]);

Solution

  1. Step 1: Understand how to update array signals

    Signals hold values immutably; to add an item, create a new array with the old items plus the new one.
  2. Step 2: Check each option's correctness

    numbers.update(list => [...list, 7]); uses update() with a function that returns a new array including 7, which is correct.
    numbers.set(numbers() + 7); tries to add 7 to an array directly, causing a type error.
    numbers = signal([...numbers(), 7]); tries to reassign the signal variable, which is incorrect.
    numbers.push(7); calls push() on the signal itself, which is not valid.
  3. Final Answer:

    numbers.update(list => [...list, 7]); -> Option D
  4. Quick Check:

    Use update() with function returning new array [OK]
Hint: Use update(fn) to immutably add items to array signals [OK]
Common Mistakes:
  • Trying to mutate signal value directly
  • Reassigning signal variable instead of updating
  • Using set() with wrong value type