Skip to content

Signals API

Reference for the Signal module, plus the related Computed and Effect entry points.

This page covers the Signal module directly and links out to Computed and Effect where their behavior intersects with signals.

Signal

Type

1type t<'a>

A signal stores a value of type 'a, plus the bookkeeping needed for dependency tracking and scheduling.

Functions

make

1let make: (
2 'a,
3 ~name: option<string>=?,
4 ~equals: option<('a, 'a) => bool>=?,
5) => t<'a>

Create a signal with an initial value. ~name is only for debugging. ~equals overrides the default strict equality check.

get

1let get: t<'a> => 'a

Read the current value and subscribe the active computed or effect, if one exists.

peek

1let peek: t<'a> => 'a

Read the current value without creating a dependency.

set

1let set: (t<'a>, 'a) => unit

Replace the signal value. Dependents are notified only if the equality check says the value changed.

update

1let update: (t<'a>, 'a => 'a) => unit

Compute the next value from the current one. Prefer this when the write depends on the existing state.

batch

1let batch: (unit => 'a) => 'a

Defer scheduler flushing until the batch completes, then return the callback result.

untrack

1let untrack: (unit => 'a) => 'a

Run a block without dependency capture. Use this when peek is too narrow and a full untracked region is clearer.

Behavior Notes

  • Default equality is strict equality:=== is used unless you pass ~equals
  • Reads can be tracked or untracked: use get for subscriptions, peek or untrack for snapshots
  • Updates are synchronous: dependents flush immediately unless wrapped in batch
  • Computeds are just signal values at the type level: read them with get or peek

Companion Modules

Most signal-heavy code also uses Computed and Effect. Their key entry points are:

1Computed.make : (
2 unit => 'a,
3 ~name: option<string>=?,
4 ~equals: option<('a, 'a) => bool>=?,
5) => Signal.t<'a>
6
7Computed.dispose : Signal.t<'a> => unit
8
9Effect.run : (
10 unit => option<unit => unit>,
11 ~name: option<string>=?,
12) => unit
13
14Effect.runWithDisposer : (
15 unit => option<unit => unit>,
16 ~name: option<string>=?,
17) => {dispose: unit => unit}

In Practice

Examples

1open Xote
2
3let count = Signal.make(0)
4let doubled = Computed.make(() => Signal.get(count) * 2)
5
6Effect.run(() => {
7 Console.log2("count", Signal.get(count))
8 Console.log2("doubled", Signal.get(doubled))
9 None
10})
11
12Signal.update(count, n => n + 1)
1type filters = {query: string, page: int}
2
3let filters = Signal.make(
4 {query: "", page: 1},
5 ~equals=(a, b) => a.query == b.query && a.page == b.page,
6)

Where to Go Next

See Also