How I became a conference speaker (and how you can too!)
This is how I got into conference speaking as a software engineer, and how you can too.
The secrets of Angular, new computed signals versus old getters
Maksym Byelous - 3 min read
I distinctly remember when I met my first getter in an Angular application. At that time it looked to me like pure magic. Functions return the result of some calculations whenever changes are applied to values - magic right? It could be based on input changes or by the act of assigning a new value to a variable, either way, the getter is triggered, recalculation happens and the returned value of the getter is as good as new. Happiness levels of us developers are at an all-time high at this moment, it seems to be all we want, automatic recalculations.
I was happy for a while... until the moment when I was not. One nice day I got knocked with the reality check of how getters work under the hood.
Getters trigger recalculations not based on specific variable changes, but on many other changes happening around in the digital world of your application. Because of this, you will see that most of the time getters are called because of unrelated changes. It could be triggered by scrolling, for example. I have a real world application example of a simple 300 lines component where one getter is triggered around 260 times when the component is visible on the page. This is something that really could negatively impact the performance of your application. Of course it also depends on the complexity of the specific component and the page where it is used. I was no longer happy with the getter solution, so I asked myself if I was able to do anything to improve this.
Some people recommend using onPush
change detection, but this defeats the purpose since now we need to handle change in
the component manually. And we want the exact opposite, automatic value updates.
In case you are okay with this, onPush
still does not change the fact that getters could be triggered by an unrelated change, when manually marking our
component for check.
This is where I looked into computed signals, we know that computed signals are called specifically based on a change of a signal that it depends on. So maybe, it is our saviour.
Let's check a simple example:
export class AngularGetterComponent { // Getter data dataSet1: number[] = [1]; dataSet2: number[] = [2]; get accDataByGetter(): number[] { console.log('getter'); return [...this.dataSet1, ...this.dataSet2]; } updatePropDataSet(num: number) { this.dataSet2.push(num + 1); } // Signal data dataSet3 = signal<number[]>([3]); dataSet4 = signal<number[]>([4]); accDataBySignal = computed<number[]>(() => { console.log('signal'); return [...this.dataSet3(), ...this.dataSet4()]; }); updateSignalDataSet(num: number) { this.dataSet4.update((prev) => [...prev, num]); } }
It is very basic, just one component which logs every time when we trigger the getter or computed signal, and both values are displayed in html.
<section> <span>Getter list:</span> @for(getItem of accDataByGetter; track $index) { <button type="button" (click)="updatePropDataSet(getItem)"> {{ getItem }} </button> } </section> <section> <span>Computed list:</span> @for(sigItem of accDataBySignal(); track $index) { <button type="button" (click)="updateSignalDataSet(sigItem)"> {{ sigItem }} </button> } </section>
Live example can be found here: Getter - signal example
First thing we could notice in the console is that during initiation of the component the getter is called a couple of times whereas the computed signal does only trigger once.
When we update a signal, which is tracked by computed
, we see that the computed signal does trigger once,
but our unrelated getter is triggered again a few times. We don’t want the getter to do anything when we change the signal.
When trying to update values of data properties used for getters, we see that the getter is called many times again. But most importantly, the computed signal in this case does nothing! The computed signal eliminates unnecessary calculations, finally everything goes the way it should, magic.
Even if there is an earthquake happening, the computed signal does not care about it, it sits and waits until its buddy signal changes. I’d recommend we check our components for usage of getter/setter to be sure it does not do extra unexpected work. It's a real major advantage of signals we could already have today, so don’t wait!