Pular para conteúdo

Aula 17 - Arquitetura com Standalone Components e Signals 🚦

Objetivo Pedagógico

Objetivo: Construção de aplicações Angular modernas baseadas em Standalone Components sem NgModules e reatividade granular orientada a Signals.


📑 1. Fundamentos Teóricos & Análise Técnica

O ecossistema Angular passou por sua maior transformação estrutural com a consolidação dos Standalone Components e o motor de reatividade Signals. Historicamente, o Angular dependia do conceito de NgModule para declarar dependências, diretivas e serviços de compilação. Essa abordagem adicionava alto nível de boilerplate e dificultava o tree-shaking e a modularização limpa.

Com os Standalone Components (standalone: true): 1. Cada componente declara diretamente no seu decorador @Component as dependências de template necessárias no array imports. 2. A aplicação pode ser inicializada via bootstrapApplication() a partir de uma função simplificada, sem módulo raiz.

Em conjunto, a introdução dos Angular Signals (baseados nas primitivas signal(), computed() e effect()) resolve o custo de desempenho da biblioteca Zone.js. Em vez de disparar uma checagem de detecção de mudanças (dirty checking) de cima a baixo na árvore inteira de componentes a cada evento assíncrono, os Signals permitem que o Angular saiba com precisão cirúrgica qual nó do DOM depende de qual valor reativo, permitindo a arquitetura Zoneless.

📐 Arquitetura Conceitual & Diagrama de Fluxo

flowchart TD
    subgraph ZoneJS ["Detecção Legada (Zone.js)"]
        Event["Evento / Timer"] --> RootCheck["Check Componente Raiz"]
        RootCheck --> C1["Check Filho 1"]
        RootCheck --> C2["Check Filho 2"]
        C2 --> C3["Check Neto 1 (Dirty Checking Global)"]
    end
    subgraph Signals ["Reatividade Granular (Signals)"]
        Sig["signal.set(novoValor)"] --> DirectDOM["Atualização Direta do Nó DOM Vinculado!"]
    end
    style ZoneJS fill:#ffebee,stroke:#c62828
    style Signals fill:#e8f5e9,stroke:#2e7d32

🔍 Pilares e Diretrizes Técnicas

Nesta unidade, aprofundamos os seguintes conceitos fundamentais: - Eliminação de NgModules: Arquitetura direta, concisa e orientada a componentes independentes. - Detecção de Mudanças Cirúrgica: Atualização reativa apenas dos nós inscritos, abrindo caminho para o modo Zoneless. - Sinal Computado (computed): Valores derivados puros com memoização automática que só recalculam quando suas dependências mudam. - Interoperabilidade com RxJS: Uso de toSignal() e toObservable() para transitar suavemente entre fluxos reativos.


🛠️ 2. Implementação Prática em Angular 17+ e Signals

Abaixo está a implementação técnica de referência, estruturada com padrões de engenharia de software e foco em robustez:

// counter.component.ts (Standalone Component com Signals)
import { Component, signal, computed, effect } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-counter',
  standalone: true,
  imports: [CommonModule],
  template: `
    <div class="counter-container">
      <h2>Contador Reativo: {{ count() }}</h2>
      <p>Dobro do Valor (Computado): {{ doubleCount() }}</p>
      <div class="actions">
        <button (click)="increment()">Incrementar (+1)</button>
        <button (click)="reset()">Zerar</button>
      </div>
    </div>
  `
})
export class CounterComponent {
  // 1. Sinal Writable
  readonly count = signal<number>(0);

  // 2. Sinal Derivado Computado (Memoizado)
  readonly doubleCount = computed(() => this.count() * 2);

  constructor() {
    // 3. Efeito colateral reativo
    effect(() => {
      console.log(`[Efeito] O valor atual do contador é: ${this.count()}`);
    });
  }

  increment(): void {
    this.count.update(value => value + 1);
  }

  reset(): void {
    this.count.set(0);
  }
}

💡 Análise Passo a Passo do Código

  1. Declaração Standalone: standalone: true elimina a necessidade de registrar o componente em arquivos app.module.ts.
  2. Sinal Escrita e Atualização: count.update(v => v + 1) altera o estado de forma atômica e avisa aos dependentes.
  3. Memoização com Computed: doubleCount só recalcula a multiplicação quando o valor de count() sofre mutação.

🎯 3. Próximos Passos & Sequência Didática