---
title: "Control flow não é só sintaxe mais limpa"
description: "Uma lente de review para control flow no Angular: quando migrar templates tocados, como escolher `track` e onde `@switch` ajuda a modelar estados."
deck: "`@if`, `@for` e `@switch` são mais úteis quando deixam estados de UI e identidade de lista explícitos. O [control flow nativo](https://angular.dev/guide/templates/control-flow) ficou stable no Angular v18 (maio/2024) depois que a [RFC #50719](https://github.com/angular/angular/discussions/50719) fechou. Em produção, o ganho não é sintaxe; é o que os novos blocos forçam o time a nomear."
author: "André Ramos"
url: "https://andreramos.dev/pt/angular/control-flow-not-just-cleaner-syntax/"
lang: "pt-BR"
type: "article"
---

# Control flow não é só sintaxe mais limpa

> `@if`, `@for` e `@switch` são mais úteis quando deixam estados de UI e identidade de lista explícitos. O [control flow nativo](https://angular.dev/guide/templates/control-flow) ficou stable no Angular v18 (maio/2024) depois que a [RFC #50719](https://github.com/angular/angular/discussions/50719) fechou. Em produção, o ganho não é sintaxe; é o que os novos blocos forçam o time a nomear.

## Limpo não basta

Eu gosto do control flow novo porque ele reduz malabarismo de template, mas 'sintaxe mais limpa' não é motivo forte para abrir uma migração ampla. Em app maduro, eu quero que a mudança exponha uma decisão real de UI: loading, erro, vazio, pronto, identidade ou estado finito.

Esse recorte mantém a migração útil. Um template já tocado pode ficar mais fácil de revisar sem transformar a base inteira em campanha de sintaxe.

## O que cada bloco deve provar

| Bloco | Bom uso em produção | Pergunta de review |
|---|---|---|
| `@if` | Substituir branches espalhados em `ng-template` | O caminho principal e o fallback ficaram mais fáceis de ler? |
| `@for` | Renderizar listas dinâmicas com identidade explícita | O `track` usa id estável ou só conveniência? |
| `@empty` | Tornar estados vazios visíveis | A UI antiga renderizava nada sem explicar? |
| `@switch` | Representar estados de UI mutuamente exclusivos | O estado é finito e tipado? |
| `@defer` | Adiar UI realmente pesada | Qual JavaScript sai do caminho inicial? |

## A decisão de identidade da lista

`@for` exigir `track` não é burocracia. Ele força o time a decidir como o DOM se relaciona com os dados. Isso importa para linhas com inputs, foco, animação e componentes repetidos com estado interno.

Se o backend entrega um id estável, use. Se não entrega, pergunte se a UI está escondendo um problema de modelagem. Usar identidade do objeto ou index pode servir para listas estáticas, mas não deveria ser o default para dados dinâmicos de produto.

Eu questionaria `track $index` em uma lista de produto que pode ser ordenada ou filtrada. Ele pode preservar estado na linha errada quando a ordem muda, que é exatamente o tipo de bug que uma migração de sintaxe não deveria introduzir.

*Identidade ruim em lista dinâmica*

```html
@for (order of filteredOrders(); track $index) {
  <app-order-row [order]="order" />
}
```

*Estado de template com identidade explícita*

```html
@switch (ordersState()) {
  @case ('loading') {
    <app-orders-skeleton />
  }
  @case ('empty') {
    <app-empty-orders />
  }
  @case ('ready') {
    @for (order of orders(); track order.id) {
      <app-order-row [order]="order" />
    }
  }
}
```

## Uma migração que eu aceitaria

Eu aceitaria um PR de control flow quando o time já está mexendo na tela e o diff melhora uma de três coisas: modelo de estado mais claro, decisão correta de `track` ou estado vazio/fallback útil.

Eu questionaria um PR no repositório inteiro que só troca sintaxe. O código pode compilar, mas o custo de review é real e o produto não aprendeu nada.

## Artefato reaproveitável: Checklist de review para control flow

- Migre templates já tocados, não o repositório inteiro por default.
- Use `@for` com identidade estável para dados dinâmicos.
- Adicione `@empty` quando a UI antiga não mostrava nada.
- Use `@switch` para estados finitos em vez de condições empilhadas.
- Use `@defer` apenas quando ele muda custo de carregamento ou experiência.

## Fontes consultadas

- https://angular.dev/guide/templates/control-flow
- https://angular.dev/reference/migrations/control-flow
- https://angular.dev/guide/templates/defer
- https://github.com/angular/angular/discussions/50719
- https://blog.angular.dev/meet-angulars-new-control-flow-a02c6eee7843
- https://blog.angular.dev/angular-v18-is-now-available-e79d5ac0affe

## Leia também

- [Standalone sem transformar NgModules em vilões](https://andreramos.dev/pt/angular/standalone-without-ngmodule-dogma/)
- [Um plano de 30 dias para modernizar apps Angular maduros](https://andreramos.dev/pt/angular/angular-30-day-modernization-plan/)
- [Como eu adotaria Signal Forms agora que são estáveis no Angular 22](https://andreramos.dev/pt/angular/signal-forms-not-my-default-yet/)
