Pular para o conteúdo
< samuelsantana.dev />
Voltar para o BlogDiagrama: Zone.js verifica cinco componentes (header, cart, sidebar, footer, modal); com signal(), só o cart é atualizado

O Renascimento do Angular: Signals e a Nova Abordagem HTTP

Samuel Santana
Publicado em 07 de julho de 2026(Editado em 25 de julho de 2026)
AngularPerformance

Se você acompanha o ecossistema Angular de perto, sabe que o framework está passando pelo seu maior renascimento desde a reescrita do AngularJS para o Angular 2. Com a chegada das versões 16 e 17, e a consolidação nas versões mais recentes (18 a 22), o Google mudou as regras do jogo.

O foco agora é claro: Developer Experience (DX), performance e menos boilerplate. E no centro dessa mudança estão duas peças fundamentais: os Signals e a modernização do HttpClient.

Neste artigo, vamos dissecar como essas ferramentas mudam a forma como arquitetamos aplicações escaláveis.

O que são Signals e por que você deveria se importar?

Durante anos, o Angular confiou no Zone.js para detectar mudanças. O problema? O Zone.js é uma "marreta". Ele intercepta eventos assíncronos (cliques, timeouts, requisições HTTP) e, na dúvida, verifica a árvore de componentes inteira para ver se algo mudou — ao menos os componentes com a estratégia Default (hoje Eager); os OnPush são pulados quando não foram marcados. Em aplicações complexas, como plataformas SaaS multi-tenant com painéis de dados densos, isso gera gargalos de performance.

Os Signals trazem a reatividade de grão fino (fine-grained reactivity). Um Signal é um wrapper ao redor de um valor que notifica os consumidores apenas quando esse valor realmente muda. O framework passa a saber quais componentes leem aquele Signal e marca só esses para atualização, sem depender do Zone.js para descobrir que algo mudou.

Os 3 Pilares dos Signals:
  1. signal(): O estado mutável básico.
  2. computed(): Estado derivado puro. Ele só é recalculado se os Signals dos quais depende mudarem, e o valor é guardado em cache (memoizado).
  3. effect(): Efeitos colaterais (como salvar no localStorage ou sincronizar uma biblioteca imperativa; para mexer no DOM depois da renderização, a API indicada é afterRenderEffect()) que rodam automaticamente quando suas dependências mudam.

Exemplo prático de uso:

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

@Component({
  selector: 'app-cart',
  imports: [CurrencyPipe],
  standalone: true,
  template: `
    <div>
      <p>Quantidade: {{ quantity() }}</p>
      <p>Preço Total: {{ totalPrice() | currency }}</p>
      <button (click)="increment()">Adicionar Item</button>
    </div>
  `
})
export class CartComponent {
  // Estado básico
  quantity = signal(1);
  unitPrice = 50.00;

  // Estado derivado (só recalcula quando quantity mudar)
  totalPrice = computed(() => this.quantity() * this.unitPrice);

  constructor() {
    // Efeito colateral focado em observabilidade ou debug
    effect(() => {
      console.log(`O valor do carrinho mudou para: ${this.totalPrice()}`);
    });
  }

  increment() {
    this.quantity.update(q => q + 1);
  }
}
Casos de Uso e Vantagens
  • Vantagem: Previsibilidade e performance. Mas não é o fim do ExpressionChangedAfterItHasBeenCheckedError: a própria documentação avisa que propagar estado com effect() ainda pode dispará-lo.
  • Casos de Uso: Gerenciamento de estado local complexo, formulários dinâmicos e interfaces de alta interatividade (como dashboards em tempo real).

A Nova Abordagem HTTP: Adeus Módulos, Olá Fetch API

Junto com a reatividade, a forma como o Angular lida com injeção de dependências e requisições de rede evoluiu. O antigo HttpClientModule está sendo deixado para trás na era dos Standalone Components.

A partir do Angular 15 (e consolidado como padrão no 17+), a recomendação é utilizar o provideHttpClient(). Mais do que uma mudança de sintaxe, essa nova API trouxe o withFetch().

O poder do withFetch()

Historicamente, o HttpClient usava a API XMLHttpRequest por baixo dos panos. Ao habilitar o withFetch() (do Angular 16.1 ao 21), o Angular passa a usar a Fetch API nativa. No Angular 22, o fetch virou o backend padrão e o withFetch() foi descontinuado: provideHttpClient() já basta, e withXhr() existe para quem precisa de progresso de upload, que a Fetch API não reporta. Em Server-Side Rendering (SSR) ou Static Site Generation (SSG), use o fetch: o suporte a XHR no servidor está descontinuado.

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withFetch } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withFetch()) // Angular 16.1–21; no 22+, basta provideHttpClient()
  ]
};

Unindo os Dois Mundos: RxJS vs Signals

A pergunta que todo recrutador técnico ou Tech Lead faz hoje é: "Os Signals vão matar o RxJS?"

A resposta de um engenheiro sênior é: Não. Eles resolvem problemas diferentes.

O RxJS é excepcional para lidar com eventos assíncronos ao longo do tempo (como debouncing de inputs ou WebSockets). Já os Signals são perfeitos para estado síncrono. A beleza do Angular moderno está na interoperabilidade. Com o pacote @angular/core/rxjs-interop, podemos fazer requisições HTTP (que retornam Observables) e transformá-las em Signals de forma elegante com o toSignal:

import { Component, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';

interface User {
  id: number;
  name: string;
}

@Component({
  selector: 'app-user-profile',
  standalone: true,
  template: `
    @if (user(); as user) {
      <h1>{{ user.name }}</h1>
    } @else {
      <p>Carregando...</p>
    }
  `
})
export class UserProfileComponent {
  private http = inject(HttpClient);
  
  // Transforma o Observable da requisição HTTP diretamente em um Signal
  user = toSignal(this.http.get<User>('/api/user/1'));
}

Nota: A nova sintaxe de Control Flow (@if, @for) do Angular 17+ combina perfeitamente com Signals.

Para leituras reativas como esta, o Angular 22 estabilizou o httpResource() (de @angular/common/http): ele faz a requisição pelo próprio HttpClient (interceptors incluídos), expõe value(), isLoading() e error() como Signals e cancela a requisição pendente quando a URL reativa muda. Para mutações (POST, PUT), a documentação recomenda continuar usando o HttpClient diretamente.

Conclusão

A engenharia de software é sobre adotar os padrões corretos para resolver gargalos de escala. A migração mental para os Signals e o uso do novo HttpClient com Fetch API não são apenas "hype". São ferramentas tangíveis que reduzem a carga cognitiva do desenvolvedor e, com o modo zoneless (padrão desde o Angular 21), tiram o Zone.js do bundle e cortam ciclos de detecção de mudanças desnecessários.

Comentários

Carregando comentários...