when
when observes a predicate and fires once when it becomes true, then disposes
itself. It has two forms: callback-based and promise-based.
Signature
// Callback form — returns Dispose
function when(
predicate: () => boolean,
effect: () => void,
options?: WhenOptions,
): Dispose
// Promise form — returns cancellable promise
function when(
predicate: () => boolean,
options?: WhenOptions,
): WhenPromise
type WhenPromise = Promise<void> & { cancel: () => void }
interface WhenOptions {
name?: string
timeout?: number
onError?: (error: Error) => void
signal?: AbortSignal
}
Parameters
| Parameter | Type | Description |
|---|---|---|
predicate |
() => boolean |
Tracked function — checked on every dependency change |
effect |
() => void |
Runs once when predicate returns true (callback form only) |
options.name |
string |
Debug name |
options.timeout |
number |
Milliseconds before auto-dispose with error |
options.onError |
(error) => void |
Error handler (callback form only) |
options.signal |
AbortSignal |
Aborts the when reaction when signaled |
Callback form
import { observableBox, when } from "@fobx/core"
const ready = observableBox(false)
const dispose = when(
() => ready.get(),
() => console.log("Ready!"),
)
ready.set(true)
// prints: Ready!
// when is automatically disposed
If the predicate is already true on the first run, the effect fires
synchronously:
const flag = observableBox(true)
when(
() => flag.get(),
() => console.log("immediate"),
)
// prints: immediate (synchronously)
Promise form
Omit the effect to get a promise that resolves when the predicate becomes true:
const loading = observableBox(true)
const waitForData = when(() => !loading.get())
loading.set(false)
await waitForData
console.log("data loaded")
Cancel
The returned promise has a cancel() method:
const promise = when(() => data.get() !== null)
// Later, if no longer needed:
promise.cancel() // rejects with "When reaction was canceled"
Timeout
when(
() => ready.get(),
() => console.log("ready"),
{
timeout: 5000,
onError: (err) => console.error(err.message),
// prints: "When reaction timed out" after 5 seconds
},
)
For the promise form, a timeout rejects the promise.
AbortSignal
const controller = new AbortController()
const promise = when(
() => done.get(),
{ signal: controller.signal },
)
controller.abort() // rejects with "When reaction was aborted"