Angular ‐ Signals - FullstackCodingGuy/Developer-Fundamentals GitHub Wiki

What are Signals?

  • Signals are a specific type of observable designed to optimize change detection for asynchronous data.
  • Signals are reactive in nature and has this producer-consumer design.
  • Signals are a new feature that tracks changes in a variable’s value and notifies us reactively when a change occurs.
  • Signals provide a new way to capture when a variable undergoes a data change, making the code more reactive
  • A signal is a variable + change notification
  • A signal is reactive, and is called a "reactive primitive", (want to know when the value is set or updated)
  • A signal always has a value
  • A signal is synchronous
  • A signal is not a replacement for RxJS and Observables for asynchronous operations, such as http.get
  • Signals are a synchronous execution model. One synchronously reads/writes values from/to the signals. If you want to process async code, most signal implementations have some “effect” APIs that allow you to do so.

Where can we use signals?

  • Use them in components to track local component state
  • Use them in directives
  • Use them in a service to share state across components
  • Read them in a template to display signal values
  • Or use them anywhere else in your code
  • Use a signal or a computed signal in a component for any state that could change. In this context, state refers to any data that the component manages. Everything from an isLoading flag to the current displayed "page" of data to the user's selected filter criteria could be signals. Signals are especially useful when displaying data in the template when that data should react to other actions.

Highlights

  • The Angular team calls this the golden rule of signal components: "change detection for a component will be scheduled when and only when a signal read in the template notifies Angular that it has changed."
  • If a signal is changed, any consumer interested in reading that signal is notified. But the consumer is not given the new value. The next time it's their turn to execute, the consumer reads the current value from the signal.
  • If you are familiar with RxJS and Observables, signals are quite different. Signals don't emit values like Observables do. And signals don't require a subscription.

Operations

  • The set() method replaces a signal with a new value, metaphorically replacing the contents of the signal box. Pass the new value into the set method. image

  • The update() method updates the signal based on its current value. Pass to the update method an arrow function. The arrow function provides the current signal value so you can update it as needed. In the code below, the quantity is doubled. image

  • The mutate() method modifies the content of a signal value, not the signal value itself. Use it with arrays to modify array elements, and objects to modify object properties. In the code below, a vehicle's price is increased by 20%. image

  • Regardless of how the signal is modified, consumers are notified that the signal was changed. The consumers can then read the new signal value when it's their turn to execute.

Computed Signal

  • Oftentimes we have variables in our code that depend on other variables. For example, the total price for an item is the price for that item times the desired quantity of that item. If the user changes the quantity, we want to change the total price. For that, we use computed signals.

  • Define a computed signal by calling the computed creation function. The computed() function creates a new signal that depends on other signals.

  • Pass to the computed function a computation function that performs the desired operation. The operation reads the value of one or more signals to perform its computation.

image

How to Use an Effect

  • There may be times that you need to run code when a signal changes, and that code has side effects. By side effects I mean code that calls an API or performs another operation not related to the signal. In these cases, you'll use an effect().

  • For example, you want to debug your signals and log out the signal value each time the code reacts to a change to that signal. Calling console.log() is a side effect.

  • To define an effect, call the effect() creation function. Pass to the function the operation to perform. This operation is re-executed every time the code reacts to a change in any dependent signal.

  • An effect should not change the value of any signals. If you need to change a signal based on a change to a dependent signal, use a computed signal instead.

  • You'll find that you won't use effects often. Though they are useful for logging, or calling other external APIs. (But don't use them to work with RxJS and Observables. There will be signal features to convert to and from Observables.)

Difference between Observables vs Signals

Declaration

image

Getting value

// normal console.log('Answer', answer);

// signal console.log('Answer', answer.value);

image

// observable answer.subscribe((value) => console.log('Answer', value));

Observables stand out because they are the only case in which we could not just get the value; instead, we were required to create a callback and a subscription. This difference is at the heart of the signal versus observable difference.

Subscription

One subscribes to observables by invoking the subscribe method and passing in a callback. So we call this an “explicit” subscription. (Yes, a framework can sometimes call the subscription on your behalf, but there is still a subscription.)

While signals can also have “explicit” subscriptions, most rely on “implicit” subscriptions. Let’s cover how that works.

image

image

Analysis

  • A signal is like a bucket that contains the value. You can pass the bucket around in the same way you pass the value to the rest of your application. The application can at any time look into the bucket (read) or update what is in the bucket (write).

  • But because it is a bucket, the bucket “knows” when the read or write has happened. So now an “observer” can “know” when a read or write has occurred. Being able to “know” when there is a read/write is what makes signals reactive!

  • An observable is quite different from a value or a signal. An observable is like a pipe. At any time, the pipe can deliver a new value. This has several implications. First, you can’t just look into a pipe whenever it suits you. Instead, you have to register a callback and wait for the callback to be invoked when the new value shows up. Second, observables deliver values over time. This “time” concept is core to observables. (Whereas signals have no concept of time, it is just whatever is in the bucket.)

When to use observable

The Angular documentation describes observables as a technique developers can use for things like:

  • Event handling
  • Asynchronous programming
  • Handling multiple values emitted over time
  • Observables don’t come from within Angular itself; rather, they are supplied to Angular by RxJS. An observable can emit more than once over time, so what do you do if you want to combine multiple emitters? What if you want to consolidate results from more than one source?

References