Signals
A signal holds a value that you can read and write. Use createSignal initialinside an active graph, or construct Signal (graph, initial)against an explicit graph.
createSignal returns the Signal<'T> itself. It is always ready: unlike an async source, a signal cannot be pending or failed.
Reading and writing
| Member | Meaning |
|---|---|
.Value | Reads the value and records a dependency when a memo or effect is running |
.Value <- x | Writes the value |
.Peek | Reads the value without recording a dependency |
.TryValue | Reads the value as a Reading<'T> (Ready, Pending or Failed) and records a dependency |
let count = createSignal 1
// Read
count.Value // 1
// Set
count.Value <- 2
// Read
count.Value // 2
count.Peek // 2
count.TryValue // Ready 2
Reading .Value or .TryValue inside a memo or effect records a dependency. Reading outside a computation simply returns the value. .Peek never records a dependency.
Use Signal.update count (fun value -> value + 1) to transform the current value. It reads through .Peek, so the update itself adds no dependency. The resulting write uses the same equality comparison as .Value <- value.
Propagation
A changed write marks direct observers dirty: they need to run again. Computations farther downstream are marked check: an upstream result might have changed. They bring their dependencies current before deciding whether their own bodies need to run. A mark for checking is not itself a re-run.
Effects normally finish before a write returns. Batch defers effects until the outermost batch ends; an unobserved memo refreshes only when read.
Equality
A Signal that does not change its value will not mark downstream observers:
The cutoff happens before notification. An equal write leaves the stored value and every observer unchanged. In comparison, AsyncSource.Settle always notifies its readers, even when the value is equal. A downstream memo may cut off that equal result after its own re-run, but its readers have already been marked for checking. See Async sources for the matching replay.
Choosing equality
GraphOptions.Equality supplies the comparison when each node is created:
JsIdentityPolicyis the default. Primitives and strings compare by value; reference types such as records and lists compare by identity on .NET.StructuralPolicyusesEqualityComparer<'T>.Default.
An equal copy of a record therefore propagates under the default policy on .NET. Mutating an object in place and writing the same reference back is cut off. Prefer immutable updates that create a new value; see Deep and keyed updates.
Equality covers custom policies, NaN and differences between .NET and Fable. The policy is graph-wide; individual nodes do not accept their own comparers.
Lifetime and threads
A signal stores state; it does not own a computation or cleanup. Dispose the owner of its readers to stop their work and release dependency edges.
Writes obey the graph's thread-affinity guard, including equal writes. Use graph.Dispatch for writes from another thread; see Threading and dispatch.