Computed Signals in Angular: derivare lo stato senza getter
I segnali computati, introdotti nel sistema reattivo di Angular, permettono di definire valori che si aggiornano automaticamente quando cambiano le dipendenze. Non si tratta semplicemente di una sintassi più comoda, ma di un cambio di paradigma: invece di calcolare una proprietà ogni volta che viene letta, il framework intercetta i cambiamenti delle fonti e ricalcola il risultato solo quando necessario, evitando lavoro ridondante. Questo approccio è particolarmente utile in contesti complessi, dove più pezzi di stato si influenzano a vicenda e dove prestazioni e manutenibilità sono priorità.
L’idea alla base dei segnali computati è semplice: se hai una proprietà che dipende da altre, perché calcolarla ripetutamente? Perché non lasciare al sistema il compito di monitorare i cambiamenti e aggiornarla in modo intelligente? In questo articolo esploreremo come sfruttare questa funzionalità per derivare stato in modo pulito, senza ricorrere ai getter — strumenti che, sebbene utili, presentano alcuni limiti non sempre evidenti.
I limiti dei getter
I getter sono una caratteristica familiare a chiunque abbia lavorato con JavaScript o TypeScript. Consentono di esporre una proprietà calcolata come se fosse un campo diretto, mascherando la logica dietro una semplice lettura. In apparenza, è un’astrazione comoda. Ma in pratica, nascondono alcuni problemi.
Il primo è di natura prestazionale. Ogni volta che accedi a un getter, il codice al suo interno viene eseguito. Se quel codice comprende operazioni complesse — come filtraggi, trasformazioni o chiamate di servizio — il suo costo si ripresenta a ogni lettura, anche se le dipendenze non sono cambiate. In un contesto dinamico come quello di un template Angular, che potrebbe leggere la proprietà molte volte durante un ciclo di rilevamento delle modifiche, l’impatto può accumularsi rapidamente.
In secondo luogo, i getter offuscano il flusso reattivo. Quando una proprietà calcolata non “sa” da cosa dipende, non può ottimizzare quando o se deve ricompilarsi. Resta un’entità passiva, chiamata sempre allo stesso modo, senza possibilità di cache automatica o memoizzazione intelligente. Questo rende difficile integrarli in un sistema che punta a minimizzare il lavoro ridondante.
Infine, l’uso frequente di getter può rendere il codice meno esplicito. A prima vista, user.fullName sembra un accesso diretto, ma in realtà potrebbe nascondere logica complessa. Questa opacità può confondere chi legge il codice e complicare il debug quando qualcosa non si aggiorna come previsto.
Derivare stato in modo reattivo
Una soluzione moderna a questi problemi arriva dal sistema dei segnali di Angular. I segnali computati, grazie al decoratore @computed, permettono di definire proprietà il cui valore viene calcolato in modo reattivo e memoizzato. Il sistema non solo esegue la funzione solo quando le sue dipendenze cambiano, ma lo fa in modo automatico e trasparente.
Prendiamo un esempio comune: un utente con nome e cognome, da cui vogliamo derivare il nome completo. Con un getter, la soluzione è semplice ma imperfetta:
Loading...Ogni lettura di fullName genera una nuova stringa, anche se firstName e lastName non sono cambiati. Ora, con i segnali, possiamo definire queste proprietà in modo reattivo:
Loading...Qui, fullName è un segnale computato che “osserva” i valori di firstName e lastName. Il calcolo avviene solo quando uno dei due cambia. Il risultato è memorizzato finché non ce n’è bisogno, garantendo efficienza e reattività senza sforzo aggiuntivo per lo sviluppatore.
Questa logica si estende facilmente a casi più complessi. Immagina un carrello della spesa dove il totale dipende da prezzi e quantità. Senza segnali, potresti calcolarlo in un getter, rischiando di eseguire l’operazione decine di volte per ciclo di change detection. Con un segnale computato:
Loading...Il calcolo avviene solo quando items() cambia — e solo in quel momento. Il resto del tempo, totalPrice() restituisce il valore memorizzato, rapidamente e senza overhead.
Vantaggi e uso pratico
I segnali computati portano benefici tangibili: migliore performance, codice più chiaro e una gestione dello stato più prevedibile. Non c’è bisogno di implementare cache manuali, né di preoccuparsi di quando ricalcolare. Il sistema reattivo si occupa di tutto, collegando automaticamente le dipendenze.
Un altro vantaggio è la composizione. Puoi costruire segnali computati a partire da altri segnali computati, creando una gerarchia di stato derivato che si aggiorna in modo coerente. Questo è particolarmente utile in scenari dove più livelli di logica si sovrappongono — ad esempio, un filtro in tempo reale su una lista, con conteggi aggiornati dinamicamente.
Nel template, l’uso è intuitivo. Se hai un segnale fullName, basta chiamarlo con fullName() per ottenere il valore corrente:
Loading...Angular gestisce internamente la reattività, assicurando che la vista venga aggiornata solo quando necessario, senza richiedere metodi come ChangeDetectorRef.detectChanges() o pattern complessi.
Verso un’architettura più reattiva
I segnali computati non sono una sostituzione universale per tutti i getter, ma offrono un’alternativa superiore nella maggior parte dei casi di derivazione dello stato. Quando abbandoni il modello “calcola ogni volta” a favore di uno “calcola solo se serve”, il codice diventa più efficiente e più facile da ragionare.
In futuro, con l’evoluzione del sistema reattivo di Angular, ci si può aspettare un’integrazione ancora più profonda: ottimizzazioni automatiche, strumenti di debug avanzati e una maggiore adozione nei servizi e nei componenti core. Per ora, i segnali computati rappresentano uno strumento maturo, performante e intuitivo per chi vuole sfruttare al meglio la reattività del framework.
Scegliere di usare i segnali non è solo una questione tecnica, ma un cambio di mentalità verso un modo più dichiarativo di gestire lo stato. Se stai costruendo un’applicazione scalabile, già oggi puoi trarne beneficio. La prossima volta che stai per scrivere un getter, chiediti: forse, un segnale computato farebbe un lavoro migliore.