Skip to content

untrack()

The untrack() function executes code without tracking signal reads as dependencies.

const result = untrack(fn)

fn : A function to execute. Signal reads inside this function won’t be tracked.

Whatever fn returns.

Use untrack() when you need to read signals for context or logging without triggering re-runs when those signals change:

const a = signal(1);
const b = signal(2);
const sum = computed(() => {
// Depends on `a`, but NOT on `b`
return a() + untrack(() => b());
});
sum(); // 3
a(10);
sum(); // 12 (recomputed because `a` changed)
b(20);
sum(); // 12 (not recomputed — `b` isn't a dependency)
  • sig.peek() — single signal
  • untrack(fn) — multiple signals
const x = count.peek();
const { a, b, c } = untrack(() => ({ a: sigA(), b: sigB(), c: sigC() }));

Only depend on some signals based on a condition:

const useCache = signal(true);
const cache = signal({});
const fetchData = signal(() => { ... });
const data = computed(() => {
if (useCache()) {
// Only track cache when useCache is true
return cache();
}
// Don't track fetchData — just call it
return untrack(() => fetchData()());
});

Log values without creating dependencies:

effect(() => {
const value = importantSignal();
// Log other context without depending on it
untrack(() => {
console.log('Context:', otherSignal(), anotherSignal());
});
doSomethingWith(value);
});

Avoid infinite loops when an effect needs to read and write the same signal:

effect(() => {
const trigger = someTrigger();
// Read count without creating a dependency
const current = untrack(() => count());
if (trigger && current < 10) {
count(current + 1);
}
});
  • signal()peek() for single-signal untracked reads
  • effect() — Where tracking matters most
  • computed() — Derived values with automatic tracking