ReactionAPI reference for Reaction in Semantic UI's reactivity systemrefresh-cwAPI Reference
Categories

Reaction

A reaction is a computation that re-runs whenever the signals it read change. Use it for side effects and computations that respond to reactive state.

Creating

reaction

reaction(callback, options);

Creates a reaction and runs it once immediately, tracking the signals the callback reads. It re-runs whenever any of them change. The callback receives the Reaction instance.

Parameters

Name Type Description
callback function Runs reactively, receiving the reaction instance
options object Optional configuration
Options
Name Type Default Description
firstRun boolean true Run the callback immediately on creation. Set false to create the reaction without an initial run
context object undefined Debugging context surfaced in tracing output. See Debugging Reactivity

Returns

The created Reaction.

Usage

import { signal, reaction } from '@semantic-ui/reactivity';
const count = signal(0);
const counter = reaction(() => {
console.log('count is', count.get());
});
count.set(1); // logs: count is 1

Pass firstRun: false to defer the initial run until you call run() yourself.

const deferred = reaction(() => {
console.log(count.get());
}, { firstRun: false });
deferred.run(); // tracks dependencies and logs for the first time

Example

Running

run

reaction.run();

Executes the callback, rebuilding the tracked dependency set from scratch. Called automatically on creation and whenever a dependency changes. Call it manually to force a re-run or to perform the first run of a reaction created with firstRun: false.

Lifecycle

onCleanup

reaction.onCleanup(callback);

Registers a cleanup callback that fires just before the reaction’s next run and once when it stops. Use it to tear down resources or scope inner reactions to this one.

Parameters

Name Type Description
callback function Runs on the next re-run or on stop

Cleanups fire in registration order, and the queue is cleared after firing. A cleanup registered during firstRun fires once, before the second run.

Usage

const channel = signal('updates');
reaction((comp) => {
const socket = subscribe(channel.get());
// tears down the old socket before resubscribing, and on stop
comp.onCleanup(() => socket.close());
});

stop

reaction.stop();

Permanently stops the reaction. It unsubscribes from every dependency, fires its cleanups, and no longer responds to changes. Idempotent.

Usage

const count = signal(0);
const counter = reaction((comp) => {
console.log(count.get());
if (count.get() > 5) {
comp.stop(); // detach once the threshold is crossed
}
});
count.set(6); // logs 6, then stops
count.set(7); // no output

Example

Async Reactions

A reaction callback may be async. Return a promise and the run is treated as asynchronous: the reaction tracks the signals read before the first await, then stays in flight until the promise settles.

import { signal, reaction } from '@semantic-ui/reactivity';
const userId = signal(1);
const user = signal(null);
reaction(async (comp) => {
const id = userId.get(); // tracked, read before the first await
const res = await fetch(`/api/users/${id}`, { signal: comp.abortSignal });
user.set(await res.json()); // writes never need track
});

Runs never overlap. When a dependency changes while a run is in flight, the reaction aborts that run’s abortSignal and coalesces every change into a single re-run. The re-run starts once the in-flight promise settles, so the latest run wins and intermediate states never launch a run of their own. Rejections report through console.error and never surface as unhandled rejections.

An async re-run starts at the flush drain point, after pending sync reactions and before the afterFlush snapshot. firstRun stays true through the whole first run, including continuations after an await, and flips once the promise settles.

track

reaction.track(callback);

Re-enters dependency tracking for a synchronous block after an await. Signals read inside the callback register on the reaction and accumulate into the current run, so an async reaction can depend on values it reads past its first await. Reads after an await without track() register nothing.

Parameters

Name Type Description
callback function Synchronous function whose signal reads should register on the reaction

Returns

The callback’s return value.

Usage

const query = signal('');
const page = signal(1);
reaction(async (comp) => {
const q = query.get(); // tracked normally
const results = await search(q);
const n = comp.track(() => page.get()); // page re-runs the reaction too
show(results, n);
});

abortSignal

reaction.abortSignal;

A per-run AbortSignal, created on first access and aborted when the run is superseded by an invalidation, a re-run, or stop(). Pass it to fetch or any abortable work to cancel in-flight IO when the reaction re-runs. Sync reactions get one too, the signal a run reads aborts just before the next run reads a fresh one.

Usage

const query = signal('');
const results = signal([]);
reaction(async (comp) => {
const q = query.get();
// the previous run's request aborts automatically when query changes
const res = await fetch(`/search?q=${q}`, { signal: comp.abortSignal });
results.set(await res.json());
});

Properties

firstRun

reaction.firstRun;

true while the callback is executing for the first time, false on every later run. Useful for one-time initialization.

Read the signals you depend on before any early if (firstRun) return. Bail out first and the reaction registers no dependencies and never re-runs.

Usage

const data = signal({ value: 0 });
reaction((comp) => {
const current = data.get(); // track before branching
if (comp.firstRun) {
console.log('initial setup');
} else {
console.log('value updated:', current.value);
}
});

Example

active

reaction.active;

true while the reaction is responding to changes, false once stop() has been called.

Usage

const counter = reaction((comp) => {
console.log('active:', comp.active);
});
counter.stop();
counter.active; // false

current

Reaction.current;

The reaction currently executing, or null outside a reactive run. A static mirror of Scheduler.current, kept on the class so a debugger breakpoint can read it without importing currentReaction().

Returns

A Reaction or null.

Previous
Reactive Object
Next
Resource