Skip to content

data-effect

Run an expression now and whenever a signal it read changes. Use it for side effects that no other directive covers: document title, imperative DOM APIs, third-party widgets, logging.

data-effect="document.title = $unread + ' unread'"
data-effect="el.scrollTop = el.scrollHeight"
part
key forbidden
value required: statements; the result is ignored
element style from a colour picker
pick a colour
<div data-signals="{ colour: '#0e7c86' }" data-effect="el.style.borderLeft = '8px solid ' + $colour" style="padding-left:.6rem">
<input type="color" data-bind:colour> pick a colour
</div>

Only the signals the expression actually read subscribe it. Below, changing b does nothing to the effect until useB is on.

conditional dependencies

effect ran times

<div data-signals="{ a: 0, b: 0, useB: false, runs: 0 }" data-effect="$useB ? $b : $a; $runs = @peek(() => $runs) + 1">
<div class="row"><button data-on:click="$a++">a++</button><button data-on:click="$b++">b++</button><label><input type="checkbox" data-bind:use-b> read b instead</label></div>
<p>effect ran <b data-text="$runs"></b> times</p>
</div>

Wrap a read in @peek to use a value without re-running when it changes. Writing a signal you also read is a loop and is reported as an error, so counters inside effects use @peek too.

@peek inside an effect

<div data-signals="{ n: 0, log: '' }" data-effect="$log = 'n is ' + $n + ' (peeked b: ' + @peek(() => $n * 10) + ')'">
<button data-on:click="$n++">n++</button>
<p data-text="$log"></p>
</div>

The body runs as statements with el in scope. Effects created inside another effect are disposed when the parent re-runs. When the element is removed, the effect stops.

import { effect } from 'sigmx/plugins'

Registering effect adds 101 bytes brotli (115 gzip, 225 minified) on top of the core. See bundle sizes.