In Angular 16, the introduction of the reactive primitive known as 'signals' served as a significant addition to the developer's toolbox, leading to shifts in established practices. However, this also sparked confusion among many developers. Some hastily began to convert all observables in their applications to signals, while others did the reverse. This analysis seeks to clarify how Angular applications should navigate this new landscape.
Understanding the Basics
Before diving into the intricacies, let's establish some foundational definitions:
- Stream: A stream is a sequence of asynchronous events or values.
- Signal: As described in the core team's RFC, a signal is a wrapper around a value that is capable of notifying interested consumers when that value changes.
From these definitions, we deduce a critical distinction: while a signal primarily encapsulates a value and can notify subscribers (akin to a stream) about its changes, a stream can represent a sequence of values or even events without an inherent value. Consequently, while every signal has the potential to produce a stream, not all streams are supposed to originate from signals.
Practical Implications
When it comes to state management, signals excel. They allow us to define an initial value, update it as needed, and have the application seamlessly mirror these adjustments in the template.
However, challenges arise when there's no initial value, or the value is irrelevant. Consider button clicks as an example. Here, there's no "initial click," and the event's value is usually inconsequential. We're primarily interested in the event itself. While traditional JavaScript recommends callbacks for such scenarios, RxJS introduced event streams, enhancing flexibility through operator pipelines. Given this context, signals might not be the best fit. Using them to update values that won't influence outcomes could be seen as misapplying the tool.
HTTP Requests: A Unique Stream Scenario
HTTP requests are a peculiar kind of stream. They don't begin with an initial value and emit only once. Promises handle this beautifully. At present, Angular employs RxJS for HTTP operations. While future implementations may differ, there's little rationale, as of now, for migrating these to signals. Despite its singular emission, an HTTP request remains a stream, not merely a value wrapper.
Conclusion
The architecture of contemporary Angular applications is undoubtedly evolving, adding layers of complexity. This places a greater onus on developers and architects, compelling them to select patterns whenever they incorporate reactivity judiciously.
Given the insights provided, when confronted with the choice between signals and observables, consider the nature of the reactive primitive you're aiming to represent. Discern whether you're dealing with a state or an event, and let that guide your decision-making process.
Top comments (1)
Signals and Observables are nearly opposite ways to address reactivity, a bit like the two sides of the Force, perhaps.
I think the fact that Angular became so unopinionaned in these regards may easily lead to lots of mixed-paradigm spaghetti apps, except, as you rightly observed, where teams make one choice and stick with it.
WRT to choosing, both approaches are probably interchangeable, as all you can do with one, you can do with the other, except maybe with Observables you can get away with both more concise and more testable code in general?