By Tamara Savkova (ERNI Slovakia)
Angular brings a new way to handle asynchronous data and their change detection – Angular Signals [1]. This new feature was first introduced in the early version of Angular v16 as a developer preview, and its final version was released in Angular v17. This article is an introduction to the Angular Signals feature and contains the core information about them. You will learn about what Signals are, what they are for, how they are different from other similar Angular tools, and how they can be beneficial for an Angular project.
What are Signals and how do they work?
Signals contain values, which may be changed or recomputed over time, and when the value change happens, its consumers are updated accordingly. Signals optimise the rendering updates by wisely tracking the data state changes throughout the Angular application.
This feature is similar to the other features handling asynchronous processes in Angular, but Signals bring some optimisations, making them more performant and simpler to maintain. For instance, Signals may be similar to BehaviorSubjects in wrapping the changeable value and enabling listening to the change, or to RxJS Observables. But Signals are easier to use since Observers do not have to subscribe to be notified of changes, and the subscriptions are created and destroyed automatically [5]. Signals may be confused with Observables. However, Signals represent a value that changes over time, while Observables represent a collection of events or values emitted over time [6].
Also, Signals bring improvements in change detection; these are covered in detail in the Angular University complete guide on Angular Signals [2], and the main points are as follows. In the first Angular versions, change detection had some drawbacks in efficiency. Angular was always checking whether anything had changed, and the whole component tree was checked to see if any changes had been made, and the view for every change had to be updated [4][5]. In default change detection, Angular checks all the components on the page, no matter if the consumer data has changed. On the other hand, with Signals, Angular is now able to determine exactly what data should be updated and update only them and nothing more. By eliminating the need for more complex Zone.js, Signals increase the runtime performance, make the code more reactive, and bring overall straightforwardness [2].
Signals represent a new method that can be used in Angular projects to improve them by keeping them up to date, making them simpler and therefore more maintainable, and making them more performant and efficient [4].
Types of Signals
Signals can be writable, read-only or computed. Writable Signals contain a value – a primitive or a more complex data structure which may be set and updated directly. Computed Signals do not have a directly assigned value, but it is derived from other Signals according to a derivation function. The purpose of the types of Signals cannot be changed, e.g. one cannot directly set a value to a computed Signal. The effects are not the Signal types, but they are also a useful part of the Signals. The effects’ definition contains an action on one or more Signals, and they track the Signal value; when its value changes, the effect runs. Also, the effects cannot be used for the Signals’ state change; it may lead to errors or unwanted behaviour. The effect feature is only in developer preview as of April 2024, but it would be a useful Signals enhancement. More detailed information, such as API, usage examples and more advanced topics, may be found in Angular’s documentation [1].
Performance features
The main feature of Signals is their behaviour upon value change. Because of the asynchronous processes, it is important to notify all the interested listeners to the changes, to update all the values, to destroy the listeners, and to do it only where it is needed, with high performance and reliability. Angular Signals provide solutions to achieve these goals.
Performance is improved with lazy evaluation and memoisation. Evaluation of the computed Signals occurs only when one or more of its dependent Signals are changed and the value of the computed Signal is read [1],[3]. On evaluation, only the read Signals are tracked, so if the Signal is placed, for example, in a condition that is not true, then the computed Signal in it was not read, and therefore it was not recomputed. Also, the value of the computed Signal is memoised, so the computed result is stored and reused on the next read [1],[3].
When to use
Firstly, the components’ event handlers on the user actions, such as a button click or filling an input field, should be handled as before [3]. The Signals feature can be used in a component for working with any local component states that change, in directives, or they can be read in templates to display their values. Also, the shared Signals between components may be useful in services. However, Signals are not a replacement for RxJS and Observables for asynchronous operations.
The effects may be useful in specific cases, like debugging with logging data on changes, or enabling custom DOM behaviour or rendering.
This article provides an overview on Signals, but there are more advanced ways to use the effects and Signals in general, which provide more flexible tools for reaching specific performance and behaviour goals.
Conclusion
This was a basic overview on Signals, which represent another advance in Angular’s capabilities of reactive programming and change detection [3]. There is more to discover on this topic, like the advanced features provided by the effects. Signals are going to improve in the future, bringing new tools for customisation, more enhancements in change detection and finalisation of the effects feature.
Resources:
[2] Angular University – Angular Signals: Complete Guide
[3] FreeCodeCamp – Signals in Angular – How to Write More Reactive Code
[4] Medium – Angular Signals: Explained with Practical Examples