Batching and untracked
Batching
Writes flush immediately, so two writes in a row expose the state between them. Signal.batch defers the flush to the end of the block - effects run once, seeing only the final state:
open Fable.Ripple
let first = Var.create "Ada"
let last = Var.create "Lovelace"
// Runs immediately: Ada Lovelace
Signal.effect (fun () -> printfn "%s %s" first.Value last.Value) |> ignore
first.Value <- "Grace" // Grace Lovelace - a torn state
last.Value <- "Hopper" // Grace Hopper
// One flush at the end: Alan Turing
Signal.batch (fun () ->
first.Value <- "Alan"
last.Value <- "Turing"
)
Batches nest: the flush happens when the outermost one ends.
Every on.* handler in Fable.Ripple.Dom already batches its writes, so one user gesture is a single flush.
Three sources feed one subscriber. Unbatched, each write is its own flush: three dots, and the counter moves by three. Batched, the same writes reach the subscriber once:
Untracked reads
Three forms, one behaviour - read the current value without becoming a dependent:
myVar.Peek()- one read, on the source itself.Signal.peek s- the same, on aVaror aSignalalike.Signal.untracked f- a whole block, for when the reads are buried in a helper you did not write.
open Fable.Ripple
let query = Var.create "signals"
let page = Var.create 1
Signal.effect (fun () ->
printfn "searching '%s' (page %d at the time)" query.Value (Signal.peek page)
)
|> ignore
page.Value <- 2 // peeked, not tracked - nothing runs
query.Value <- "adaptive" // searching 'adaptive' (page 2 at the time)
The effect reads page without depending on it, so writing page reruns nothing. Writing query reruns the effect, and it sees the current page.