Angular Signals — Preventing Unnecessary Dependencies Using the Untracked Function
When a signal value changes, any computed()
or effect()
that depends on it will be re-evaluated. This is called tracking. However, sometimes we want to read a signal value without creating a dependency, i.e., without triggering the reactive function when its value changes. In such cases, we can use the untracked
function provided by Angular.
Let’s consider an example where we have two signals, a
and b
, and we want to log their values in an effect
:
const a = signal(0);
const b = signal(1);
effect(() => {
console.log(a(), b());
})
This effect
will run the function when either a
or b
signal emits a new value. However, let’s say we only want to log when a
changes, not when b
changes. We can achieve this by untracking the b
signal:
import { untracked } from '@angular/core';
const a = signal(0);
const b = signal(1);
effect(() => {
console.log(a(), untracked(() => b()));
})
The untrack
function runs the provided function and return its result without creating any dependencies. Now, the effect will only run when the a
signal emits a new value. We can also simplify the code by passing the signal directly to the untrack
function:
const a = signal(0);
const b = signal(1);
effect(() => {
console.log(a(), untracked(b));
})
Since signals are functions, they can be passed directly, but untrack
can wrap functions with more complex behavior:
effect(() => {
// ...read signals...
const a = a();
untracked(() => {
this.someMethodThatReadsSignals(a);
});
})
In this example, any signal reads by someMethodThatReadsSignals
won’t be counted as dependencies of this effect.
In conclusion, the untracked
function is a useful tool in Angular for improving signal read performance and preventing unnecessary dependencies.
Follow me on Medium or Twitter to read more about Angular and JS!