Reactive Controls Stopping, skipping, and suppressing reactive updates sliders Guide
Categories

Reactive Controls

reaction() provides the Reaction instance as the first argument, which can be used to control when and whether the reaction runs.

reaction((computation) => {
console.log('Current value:', mySignal.get());
});

Stopping a Reaction

reaction.stop() permanently prevents a reaction from running again, even if its Signal dependencies change.

From the Return Value

reaction() returns the reaction instance, so you can stop it externally.

const counter = signal(0);
const watcher = reaction(() => {
console.log('Count:', counter.get());
});
counter.increment(); // reaction runs
watcher.stop();
counter.increment(); // no longer updating

From Inside the Callback

The reaction instance is also passed as the first argument, so it can stop itself based on a condition.

const percentComplete = signal(0);
reaction((computation) => {
const currentPercent = percentComplete.get();
if(currentPercent >= 100) {
computation.stop();
return;
}
console.log('Progress:', currentPercent);
});
percentComplete.increment(80);
percentComplete.increment(20); // at 100, reaction stops
percentComplete.increment(50); // no longer updating

Skipping First Run

Reactions run immediately when created to discover their dependencies. Use reaction.firstRun to skip side effects during this initial execution.

const score = signal(0);
reaction((computation) => {
const currentScore = score.get();
if (!computation.firstRun) {
console.log(`Score: ${currentScore}`);
}
});

Dependency Pitfall

Signal accesses must be reachable during the first run to register as dependencies. A common mistake is returning early on the first run, which prevents any dependencies from being established.

const score = signal(0);
// reaction wont rerun when score changes because dependency is not established
reaction((computation) => {
if (computation.firstRun) {
return;
}
console.log(`Score: ${score.get()}`);
});

Suppressing Reactivity

Nonreactive

nonreactive() reads reactive values inside a reaction without creating dependencies.

const name = signal('Alice');
const status = signal('Online');
reaction(() => {
const currentName = name.get(); // dependency created
const currentStatus = nonreactive(() => status.get()); // no dependency
console.log(`${currentName} is ${currentStatus}`);
});
name.set('Bob'); // triggers reaction
status.set('Offline'); // does not trigger reaction

Peek

signal.peek() reads a single signal’s value without creating a dependency. Same effect as nonreactive but scoped to one value.

const counter = signal(0);
const trigger = signal(false);
reaction(() => {
trigger.get(); // dependency created
const currentCount = counter.peek(); // no dependency
console.log('Count:', currentCount);
});
counter.set(1); // does not trigger reaction
trigger.set(true); // triggers reaction

See Reactive Performance for guard, which optimizes reactivity for specific patterns.

Previous
Flushing
Next
Performance