O Problema com RxJS para Estado Local

RxJS é poderoso para streams assíncronas, mas para estado simples de componentes, BehaviorSubjects adicionam complexidade desnecessária: gerenciar subscriptions, evitar memory leaks, operadores verbosos para transformações simples. Signals resolvem isso.

Signals Básicos

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

// Signal de escrita
const count = signal(0);

// Ler valor
console.log(count()); // 0

// Atualizar
count.set(5);
count.update(v => v + 1);

Computed Signals

Derivar valores reativamente sem subscription manual:

const firstName = signal('Ivan');
const lastName = signal('Reis');

const fullName = computed(() => `${firstName()} ${lastName()}`);
// Recalcula automaticamente quando firstName ou lastName mudam

console.log(fullName()); // 'Ivan Reis'

Effect para Side Effects

effect(() => {
  console.log(`Usuário mudou para: ${fullName()}`);
  // Executa automaticamente quando qualquer signal dependente muda
});

Signals em Componentes

@Component({
  selector: 'app-counter',
  template: `
    <p>Contagem: {{ count() }}</p>
    <button (click)="increment()">+1</button>
    <p>Dobro: {{ double() }}</p>
  `,
})
export class Counter {
  readonly count = signal(0);
  readonly double = computed(() => this.count() * 2);

  increment() {
    this.count.update(v => v + 1);
  }
}

Signal Inputs (Angular 17.1+)

@Component({
  selector: 'app-user-card',
  template: `<h3>{{ displayName() }}</h3>`,
})
export class UserCard {
  name = input.required<string>();
  role = input<string>('user');

  displayName = computed(() =>
    `${this.name()} (${this.role()})`
  );
}

Migrando de BehaviorSubject

// ANTES (RxJS)
private userSubject = new BehaviorSubject<User | null>(null);
user$ = this.userSubject.asObservable();
setUser(user: User) { this.userSubject.next(user); }

// DEPOIS (Signals)
private readonly _user = signal<User | null>(null);
readonly user = this._user.asReadonly();
setUser(user: User) { this._user.set(user); }

Quando Usar Cada Um

  • Signals: estado local/global, dados síncronos, propriedades de UI, formulários
  • RxJS: HTTP requests, WebSockets, eventos complexos com debounce/merge/switch, streams de dados
  • Ambos: toSignal() e toObservable() conectam os dois mundos