What Exactly Are Signals?
A Signal is a source of value
Alex Rickabaugh
Signals have gained widespread attention thanks to Solid.js, which defines them in the following way:
Signals form the foundation of reactivity in Solid. They hold values that evolve over time; whenever a signal's value is updated, everything that depends on it is refreshed automatically.
For those acquainted with RxJS, this concept might evoke comparisons to BehaviorSubject or, more broadly, multicasted values. But in contrast to BehaviorSubject, Signals would not necessitate explicit subscriptions for consumers to receive updates.
With Signals, subscriptions are managed implicitly—created and discarded without developer intervention. This behavior is somewhat analogous to what the async pipe accomplishes in RxJS. However, unlike Observables, Signals can be used outside templates without needing an explicit Subscription.
Signals make a concerted effort to abstract away some of the intricacies inherent in RxJS.
As previously mentioned, Signals represent values that change over time. Let's examine that closer.
A Practical Look at Signals in Angular
A straightforward demonstration of Signals in action is available here (Signals Example).
Here is a preview of what a potential Angular implementation might resemble.
Please note that experimenting with Signals in Angular requires Angular v16.0.0-next.0, which was just recently published.
It goes without saying that this is still experimental and not recommended for production environments.
An alternative for trying it out is the StackBlitz project, where you can import the signal folder.
The following is an illustrative example of how Signals might appear in an Angular app:
...
@Component({
selector: 'signals-not-noise',
standalone: true,
template: `
<div>Count: {{ count() }}</div>
<div>Double: {{ doubledCount() }}</div>
`
})
export class App {
count = signal(0);
doubledCount = computed(() => this.count() * 2);
constructor() {
setInterval(() => this.count.set(this.count() + 1), 1000);
}
}
Because doubleCount derives its value from count, which is a Signal, it will automatically recalculate whenever count is modified.
In essence, doubleCount has a dependency on, or is derived from, count, and this relationship is tracked automatically, ensuring updates occur whenever the source value shifts.
Through the use of computed, we can extract values from other Signals and build new ones based on them. Additionally, it's cached, so the calculation doesn't run on every access—only when the underlying value actually changes.
This results in a level of fine-grained reactivity that could enable more efficient change detection.
Regarding the function invocation in the template, calling functions in templates isn't as problematic as one might assume.
Signals and RxJS: The Relationship
One might assume that Signals will eventually supersede and replace RxJS altogether.
Yet, Signals are not particularly adept at managing race conditions. This is where RxJS will continue to play a vital role, handling asynchronous operations and complex event streams.
Interoperability is also a key feature: it's feasible to convert Signals into Observables, and conversely, to transform Observables into Signals.
For a detailed explanation, you can check out this video by Joshua Morony.
The introduction of Signals to Angular could potentially lower the barrier to entry for learning the framework, especially for newcomers.
The Potential for a New Change Detection Mechanism
This development has the potential to be revolutionary for Angular.
The advent of Signals makes a future without zone.js seem plausible.
By using Signals, it becomes possible to track changes at a much finer granularity, instead of scanning the entire component tree for updates. This capability could be leveraged to significantly enhance Angular's change detection process.
Currently, frameworks perform change detection at various levels of the DOM structure:
At the application tree level — as seen in Angular
At the component tree level — which is how React operates
At the level of individual elements — a model championed by Solid
It appears Angular is aiming for a more granular level of precision and, in doing so, intends to maintain interoperability between Signals and zone.js.
According to Alex Rickabaugh (the mastermind behind The Little-known Story Behind Angular Standalone Components and a Technical Lead on the Angular Core Team), lifecycle hooks like ngOnChanges might become obsolete in a world driven by Signals.
Noteworthy Resources
- Watch Joshua Morony's introduction to Signals in Angular on YouTube
- Explore the Stackblitz example created by Enea Jahollari
- Check out the talk Reactivity with Signals is coming to Angular featuring Brandon Roberts and Alex Rickabaugh
- Read Ryan Carniato's article The Evolution of Signals in JavaScript on DEV
