Angular Signals for Reactive State

frontend
TypeScript
architecture
strict_senior
Remix

Modern state management using Angular Signals with examples and best practices.

12/8/2025

Prompt

Angular Signals State Management

Implement reactive state management for [Application] using Angular Signals.

Requirements

1. State Structure

Define signals for:

  • [State 1] - [Data type] (e.g., user data)
  • [State 2] - [Data type] (e.g., form state)
  • [State 3] - [Data type] (e.g., UI state)

2. Signal Types to Implement

Writable Signals

For mutable state:

  • User inputs
  • Entity data
  • Configuration values
  • UI toggles

Computed Signals

For derived values:

  • Filtered lists
  • Aggregated totals
  • Formatted displays
  • Validation states

Effects

For side effects:

  • API calls on state changes
  • LocalStorage sync
  • Logging
  • Analytics tracking

3. Component Implementation

Create components using:

  • Signal-based reactive state
  • Computed values for derived data
  • Effects for side effects
  • Proper TypeScript typing

4. Service Layer

Implement services with:

  • Private writable signals
  • Public readonly signals
  • Computed values
  • Update methods
  • Async data loading

5. Benefits Over Zone.js

Leverage:

  • Fine-grained reactivity (only affected parts update)
  • Better performance
  • Automatic dependency tracking
  • Simpler mental model
  • OnPush change detection friendly

Implementation Pattern

import { Component, Injectable, signal, computed, effect } from '@angular/core'

// Component with signals
@Component({
  selector: 'app-[name]',
  template: `
    <div>
      <p>{{ [signalName]() }}</p>
      <p>Computed: {{ [computedName]() }}</p>
      <button (click)="update[Action]()">Update</button>
    </div>
  `
})
export class [ComponentName] {
  // Writable signal
  [signalName] = signal<[Type]>([initialValue])
  
  // Computed signal
  [computedName] = computed(() => {
    return /* derive from other signals */
  })
  
  constructor() {
    // Effect for side effects
    effect(() => {
      const value = this.[signalName]()
      // React to changes
    })
  }
  
  update[Action]() {
    this.[signalName].set([newValue])
    // or
    this.[signalName].update(current => /* transform */)
  }
}

// Service with signals
@Injectable({ providedIn: 'root' })
export class [ServiceName] {
  // Private writable signal
  private [dataSignal] = signal<[Type][]>([])
  
  // Public readonly access
  [data] = this.[dataSignal].asReadonly()
  
  // Computed values
  [computed] = computed(() => 
    this.[dataSignal]().filter(/* condition */)
  )
  
  async load[Data]() {
    const data = await this.api.get[Data]()
    this.[dataSignal].set(data)
  }
  
  add[Item](item: [Type]) {
    this.[dataSignal].update(items => [...items, item])
  }
  
  update[Item](id: string, updates: Partial<[Type]>) {
    this.[dataSignal].update(items =>
      items.map(item => item.id === id ? { ...item, ...updates } : item)
    )
  }
  
  remove[Item](id: string) {
    this.[dataSignal].update(items => 
      items.filter(item => item.id !== id)
    )
  }
}

Best Practices

  • Use signals for reactive state
  • Keep signals focused and single-purpose
  • Use computed() for derived values
  • Use effect() for side effects only
  • Make service signals readonly when exposing
  • Leverage TypeScript for type safety
  • Use update() for transformations
  • Use set() for replacements

Tags

angular
signals
reactive
state-management

Tested Models

gpt-4
claude-3-opus

Comments (0)

Sign in to leave a comment

Sign In
Angular Signals for Reactive State | vibeprompt.directory