O Renascimento do Angular: Dominando Signals e a Nova Abordagem HTTP
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 21), o Google mudou as regras do jogo.
O foco agora é claro: Developer Experience (DX), performance extrema e a redução drástica de boilerplate. E no centro dessa revolução 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. 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 exatamente qual nó do DOM precisa ser atualizado, sem depender do Zone.js.
Os 3 Pilares dos Signals:
signal(): O estado mutável básico.computed(): Estado derivado puro. Ele só é recalculado se os Signals dos quais depende mudarem, e o valor é guardado em cache (memoizado).effect(): Efeitos colaterais (como manipular o DOM diretamente ou salvar no localStorage) que rodam automaticamente quando suas dependências mudam.
Exemplo prático de uso:
import { Component, signal, computed, effect } from '@angular/core';
@Component({
selector: 'app-cart',
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 Absoluta: Previsibilidade e performance. O fim do famigerado erro
ExpressionChangedAfterItHasBeenCheckedError. - 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(), o Angular passa a usar a Fetch API nativa dos navegadores modernos. Isso não apenas melhora a performance e reduz o tamanho do bundle, mas é um requisito vital se você está utilizando Server-Side Rendering (SSR) ou Static Site Generation (SSG), pois o Node.js lida muito melhor com o fetch nativo.
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withFetch } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withFetch()) // Simples, limpo e performático
]
};
🌉 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';
@Component({
selector: 'app-user-profile',
standalone: true,
template: `
@if (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.
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, diminuem o tamanho da aplicação e entregam um produto final visivelmente mais rápido para o usuário. O Angular não está apenas acompanhando o mercado; ele está ditando uma nova forma de arquitetar o frontend.
Comments
Loading comments...