Skip to content

Untracked Reads

Not every read should create a dependency. Zolo offers two ways to read without tracking:

  • signal_untrack(|| { s.get() }) — any .get() inside the closure passed to signal_untrack is ignored by the tracking system. Use for one-off reads that should not become deps of an effect or computed.
  • s.peek() — a direct shortcut for an untracked read on the signal itself. Very handy inside effects for auto-increment without creating a cycle.

The complement of peek is s.modify(fn), which applies a function to the current value (s.set(fn(s.get()))) concisely — ideal for counters, accumulators and list updates.

b is read with signal_untrack inside the effect; changing b does not re-fire it.

04-untrack.zolo
Playground
// Feature: signal_untrack — read a signal without registering as a dep

// Syntax: `signal_untrack(|| { s.get() })` — the read inside

// the closure is NOT tracked.

// When to use: read-once initialization inside an effect, debug

// peeks, or to break a dependency intentionally.


use std::Signal

let a = signal(1)
let b = signal(100)

let e = effect(|| {
    let av = a.get()
    // `b` is read but NOT a dependency of this effect.

    let bv = signal_untrack(|| { b.get() })
    print("a={av} b={bv}")
})
// expected: a=1 b=100


// Changing `b` does NOT re-run the effect.

b.set(200)
b.set(300)

// Changing `a` re-runs the effect — and now sees the latest `b`.

a.set(2)
// expected: a=2 b=300

modify for incrementing and peek for internal logging without creating a dependency on logs.

07-peek-and-modify.zolo
Playground
// Feature: Signal.peek and Signal.modify — non-tracking read + functional update

// Syntax: `s.peek()` reads without subscribing; `s.modify(fn)`

// applies a function to the current value.

// When to use: peek for diagnostics or self-updates inside effects;

// modify for counter-style increments, accumulators, list pushes.


use std::Signal

let counter = signal(10)

// `s.modify(fn)` is shorthand for `s.set(fn(s.get()))`.

counter.modify(|v| { v + 5 })
print(counter.get())
// expected: 15


counter.modify(|v| { v * 2 })
print(counter.get())
// expected: 30


// `peek` reads without tracking — useful inside effects when you

// want to use the current value but not re-run when it changes.

let logs = signal(0)
let view = signal("home")

let e = effect(|| {
    let page = view.get()
    let n = logs.peek() + 1   // not a dep

    logs.set(n)
    print("nav to {page}, log #{n}")
})
// expected: nav to home, log #1


view.set("about")
// expected: nav to about, log #2

enespt-br