Os sinais angulares não são apenas mais um recurso. Eles representam uma maneira diferente de pensar no fluxo de dados. Se você vem de RXJs ou padrão @Input() / @Output()
Videiras, você pode pensar nos sinais como uma sintaxe mais simples para valores observáveis. No entanto, é como dizer que um violino é apenas um violoncelo menor. A forma do instrumento afeta o tipo de música que você cria.
Neste artigo, não vou repetir a documentação ou guiá -lo por outro exemplo. Em vez disso, apresentarei uma nova maneira de pensar que os sinais permitem, juntamente com alguns desafios reais que enfrentei ao usá -los em produção.
Sinais como variáveis reativas, não fluxos
Pense em sinais como variáveis reativasnão fluxos de dados. Esta é a principal mudança de perspectiva. Nos RXJs, normalmente empurramos os valores para baixo em um fluxo, combinamos -os e respondemos com efeitos colaterais por meio de Subscribe (). Os sinais mudam esse conceito. Você leu deles como variáveis. O Angular rastreia automaticamente as dependências e desencadeia reações.
Aqui está a melhor maneira de explicar sinais no código:
const firstName = signal('John');
const lastName = signal('Doe');
const fullName = computed(() => `${firstName()} ${lastName()}`);
Neste exemplo, o FullName é recalculado automaticamente quando o primeiro nome do nome ou o último nome muda. Você não precisa pensar em termos de lógica de mapa, combinelatest ou desmontagem. Você acabou de declarar relacionamentos.
Se isso parece vue ou solidjs, não é uma coincidência.
Gotcha #1: Dependências implícitas podem sair pela culatra
Quando você lê um sinal dentro de um () ou efeito (), faixas angulares computadas () que liam como uma dependência. Mas isso pode dar errado rapidamente quando você não está ciente dessas leituras.
let counter = signal(0);
const doubled = computed(() => {
console.log('Recomputing...');
return counter() * 2;
});
Você pode esperar que isso seja executado apenas quando o contador mudar, mas se você lê acidentalmente outro sinal dentro da mesma função (por exemplo, um sinalizador de log), ele também se torna uma dependência. De repente, alternar um sinalizador de modo de depuração começa a recalcular sua lógica de matemática.
Dica: Mantenha a lógica calculada e de efeito estreito e determinístico. Caso contrário, você terá atualizações fantasmas que não poderá depurar.
Sinais vs. rxjs: onde os sinais brilham – e onde eles não
Vamos ficar claros: os sinais não substituem os RXJs. Eles são projetados para trabalhar ao lado dele. Mas entender quando usar cada um é crítico.
Caso de uso | Sinais de preferência | Prefira rxjs |
Estado de componente local | ✓ | X |
Dados de interface do usuário derivados | ✓ | X |
Fluxos de eventos (por exemplo, digitação do usuário) | X | ✓ |
Estado compartilhado nos módulos (via sinais de serviço) | ✓ | ✓ |
Fluxos assíncronos complexos com tentativas | X | ✓ |
Sinais se destacam no valor de modelagem ao longo do tempo. RXJS se destaca na modelagem eventos ao longo do tempo.
Gotcha #2: sinais calculados não cache como você pensa
Uma coisa surpreendente que descobri: computado () não memoriza como o useMememo () do React () ou mesmo como você poderia esperar de um getter.
Cada vez que você lê a partir de um sinal computado (), a lógica é reexecutada se Suas entradas mudaram. Mas se você estiver chamando várias vezes em um modelo (digamos em *ngif e novamente em {{}}), poderá pagar o custo mais de uma vez.
Dica: Se um cálculo for caro, considere armazená -lo em uma const local na classe de componentes e apenas referenciar isso no modelo. Ou envolva -o em outro sinal.
Repensando a forma do estado: sinais adoram planos, não profundos
No Classic Angular com serviços e RXJs, é comum modelar estado como este:
const state$ = new BehaviorSubject({
user: null,
settings: {},
isLoading: false
});
Nos sinais, objetos reativos profundamente aninhados são estranhos. Você não pode dizer User (). Settings (). Theme () – isso é uma leitura em uma leitura. Em vez disso, você vai querer achatar:
const user = signalUser | null>(null);
const settings = signalSettings>({});
Dica: Modele cada parte do estado com seu próprio sinal. Você ganhará flexibilidade e controle de reatividade mais fácil.
Cenário prático: Formulário de personalização do rótulo
Digamos que você tenha um searchsidebarComponent e deseja personalizar seus rótulos de um pai. Aqui está a maneira ingênua:
@Input() labels = signalMapSidebarLabels>();
What happens if you try to derive a computed value?
labelsFinal = computed(() => {
const raw = this.labels();
return { ...raw, title: raw.title.toUpperCase() };
});
Agora, suponha que nos pais que você escreve:
search-sidebar (labels)="labelsFinal()" />
Isso funciona, mas você está chamando um sinal dentro de um sinal. E se você mudar seu modelo para
ele falha com uma incompatibilidade de tipo.
Dica: O sistema de entrada do Angular ainda não está totalmente nativo. Até que seja, achate o valor antes de passar as entradas.
Botcha #3: efeito() Corre imediatamente – e talvez novamente
Ao contrário do RXJS Subscribe (), que dispara apenas quando algo emite, o efeito () dispara uma vez na criação, mesmo que o sinal ainda não tenha mudado.
effect(() => {
console.log("API call for", userId());
});
Isso será executado uma vez imediatamente, mesmo que o UserID ainda não tenha mudado. Tenha cuidado ao colocar efeitos colaterais como chamadas HTTP ou rastreamento de análises dentro do efeito ().
Dica: Guard Effect () lógica com verificações nulas ou retornos antecipados, se necessário.
Pensamentos finais
Os sinais no Angular não são apenas uma nova sintaxe, eles são uma mudança no modelo mental. Depois de parar de pensar em observáveis e começar a pensar em variáveis que reagem, você descobrirá que seus componentes são menores, mais rápidos e mais fáceis de raciocinar.
Mas, como qualquer nova ferramenta, os sinais vêm com bordas nítidas. Conheça as compensações, aprenda os padrões e, acima de tudo, Não trate sinais como getters sofisticados. Eles são muito mais poderosos que isso, mas apenas se você entender o modelo.