Signal Options Customizing Signal behavior for equality checks and value cloning settings Guide
Categories

Signal Options

To provide more granular control over reactivity, Semantic provides several options which let you control how values are updated and compared.

The default options are designed to permit some minor performance overhead as a tradeoff for improved developer experience, but this might not fit all use-cases for Signals.

Signal options are passed as the second argument to signal().

Equality Comparison

By default, Signals use a deep equality comparison, isEqual, to determine if a new value is actually different from the current value. This prevents Reactions from rerunning if the updated value has not changed.

import { signal } from '@semantic-ui/reactivity';
const person = signal({ name: 'John', age: 30 });
// No reactive update triggered (objects are deep equal)
person.set({ name: 'John', age: 30 });
// Reactive update triggered (objects differ)
person.set({ name: 'Jane', age: 30 });

Custom Equality Function

You can provide a custom equality comparison function using the equality option to modify how equality checks are performed. This can potentially speed up comparisons at the cost of potential additional reactivity.

When To Use Custom equality functions can be useful for extremely large objects or data structures where you want to avoid checking their values each time they are accessed.

const customEquality = (a, b) => {
// Custom comparison logic (e.g., shallow compare, reference compare)
return a === b; // Example: strict reference equality
};
// Signal using custom equality check
const customVar = signal(initialValue, { equality: customEquality });

Safety

The safety option controls how a signal guards its stored value against outside mutation.

PresetStoresOn get().x = yDedupe
reference (default)the value by referencemutates the signal silentlyisEqual
clonea defensive copymutates the copy, not the signalisEqual
nonethe value by referencemutates silentlynever

reference

The default. The signal stores and returns your value as-is, with no copying. It is the fast path and the right choice for most signals, including objects you own and update through set() or the mutation helpers.

const user = signal({ name: 'Alice' });

clone

Stores and returns defensive copies, so outside code holding a reference cannot mutate the signal’s value. Reach for it when state might be changed behind your back. Copies use a deep clone by default; pass a clone function to override it.

const config = signal({ theme: 'dark' }, { safety: 'clone' });
const jsonClone = (value) => JSON.parse(JSON.stringify(value));
const data = signal({ n: 1 }, { safety: 'clone', clone: jsonClone });

none

Stores by reference like reference, but skips the equality check, so every set() notifies even when the value is unchanged. Use it for event-stream signals where each emission matters.

const pulse = signal(null, { safety: 'none' });
pulse.set({ type: 'heartbeat' });
pulse.set({ type: 'heartbeat' }); // still notifies
Previous
Debugging
Next
Query