What is Signal?, Why is getting so popular in Angular while is not a new concept or feature for reactive programming languages, Is it replaceable existing concepts like RXJS, observables, I will explain briefly
Signals are already used in different reactive languages like SolidJs, Preactjs etc.
Now introduced in angular V16, May 2023, signals only introduced for enhancement and make the application efficient , good performance, A signal is a wrapper around a value that can notify interested the consumer after change detections Change detections means, I will explain it with simple example below
eg. Let say..
let farman = 100 rupees
let mehtab = 200
let junaid = 300
let Sum;
Sum = 100 + 200 + 300 = 600
after contribution, farman father gives 200 more for contribution now we calculate the sum Sum is still 600
because sum is already logged with value 600 it will not add 100 rupees with existing sum
But In Signals,
import {Signals} from "@angular/core"
farman = Signal<number>(100)
mehtab = Signal<number>(200)
junaid = Signal<number>(300)
@Constructure() {
const effect = effect (()=> {
let sum = farman() + mehtab() + junaid()
return sum
}) }
//if we want to add additional money then signals provide to update signal to update the state farman.update(value => value + 200);
//now our component is re-render and add this value with existing one sum is now 800 rupees
Signals provide more reactivity and controls over the change detection which does the improve performance and efficiency
count = Signal<number>(0)
count() //read the value
// Signals are getter functions - calling them reads their value.
A signal is a wrapper around a value that can notify interested consumers when that value changes. Signals can contain any value from simple primitives to complex data structures.
like, number, string, boolean, array, objects and so on...
A signal's value is always read through a getter function, which allows Angular to track where the signal is used.
Signals may be either writable or read-only.
Writable signals are mutable we can change the value of writable while read only signals are immutable we can not change the value of read only signals
Note: -- By default signals are writable
We can update the value of signals by using these functions
get()
set()
update()
compute()
mutate()
effect()
Let say have count = signal(0)
Getter Signals
get() is default behavior of signal we can read the value of signal with parenthesis eg-- count() // 0 value
Setter Signals
set is basically, used for replaced the existing one eg-- count.set(2) //now value is 2
Update Signals
use the .update() operation to compute a new value from the previous one eg-- // Increment the count by 1. count.update(value => value + 1);
Computed signals
const count: WritableSignal<number> = signal(0);
const doubleCount: Signal<number> = computed(() => count() * 2);
The doubleCount signal depends on count. Whenever count updates, Angular knows that anything which depends on either count or doubleCount needs to update as well.
Mutate Signals
type Product = { category : string, price : number, model : string } const productsData = signal<Product[]>([{category : "MI", model : "POCOM2 Pro", price : 12000}]) productsData.mutate(value => {
// Change the first TODO in the array to 'done: true' without replacing it. value[0].price = 13000; });
Mutate signals is updating the array of object value without replacing the entire array
Effect Signals
Signals are synchronous but in effect function we can change it from synchronous to asynchronous. Signals are useful because they can notify interested consumers when they change. An effect is an operation that runs whenever one or more signal values change. You can create an effect with the effect function:
effect(() => { console.log(The current count is: ${count()}
); });
Effects always run at least once. When an effect runs, it tracks any signal value reads. Whenever any of these signal values change, the effect runs again. Similar to computed signals, effects keep track of their dependencies dynamically, and only track signals which were read in the most recent execution.
Effects always execute asynchronously, during the change detection process.
Reading without tracking dependencies--
Rarely, you may want to execute code which may read signals in a reactive function such as computed or effect without creating a dependency.
For example, suppose that when doubleCount() changes, the value of a count() should be logged. Creating an effect which reads both signals
effect(() => { console.log(User set to
${doubleCount()}and the counter is {$count()}
); });
This example logs a message when either doubleCount or count changes. However, if the effect should only run when currentUser changes, then the read of counter is only incidental and changes to counter shouldn't log a new message.
You can prevent a signal read from being tracked by calling its getter with untracked:
effect(() => { console.log(User set to
${doubleCount()}and the counter is ${untracked(count)}
); });
Re-Rendering
When we are different types of life cycle method why we used signals we use signals because it only render that specific part or property that changes, not render the whole component whenever signals value will change it will only re- render the specific part only
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 You can use signals in everywhere where you want
we can not only define the signals inside the component we can also define the signals outside of the component for sharing the states from parent to child component
1- Locally,
Locally scope means we only used signals state inside that component not share the state the with children components
2 Globally
In global scope, we can share the state from parent component to child component
In this diagram first one is signal second one is primitive value and third one is observable(RXJS) RXJS is reactive programming language that provides observables
let say :; count = 1 //primitive value
count = signal<number>(1) //<type of value number, string , boolean and so on>
count = from[1] //observables
console.log("Answer of normal variable", count ) //1
console.log("Answer of signals", count()) //1
console.log(Answer of observable", count.subscribe((value) => value ) //1
We consume the value of observables we used subscribe functions and re-render this value to after change detections then pass it to life cycle methods like OnChanges()
eg
constructor() { //it runs only once after first initializations ngOnInit() { this.logIt('OnInit'); } // ngOnChnages runs after every change detections ngOnChanges(){ console.log(this.count) } }
Note: Ng is nothing but short form of angular
Angular And RXJS Vision
The sub-RFC 4 proposal sparked a Discussion about the possibilities of integrating Angular Signals with Observables. It all comes down to whether Angular Signals should adopt globally understood common interop
Ben Lesh (RXJS Author) thinks that making signals fit observable chains directly is a good idea, stating that Signals inherently possess a time dimension that makes them well-suited for this. By adopting common interop points, Angular Signals could achieve better compatibility across various platforms