I have a $state
with an array:
let clicks = $state([])
I have an effect, which references the clicks
state:
$effect(() => {
// Box selection
if (autoDetectSettings.value.mode === 'box' && drawingBox && clicks.length === 2) {
const poly = objectSchema.parse({
id: createId(),
type: 'poly',
coords: [
{ x: clicks[0].x, y: clicks[0].y },
{ x: clicks[0].x, y: clicks[1].y },
{ x: clicks[1].x, y: clicks[1].y },
{ x: clicks[1].x, y: clicks[0].y },
],
color: '#ffffff',
opacity: 0.15,
stroke_color: '#ffffff',
stroke_opacity: 1,
stroke_width: 2,
blend_mode: 'normal',
})
artboard.objects.push(poly)
}
})
Adding an $inspect
shows that the value of clicks
is updating, but the effect is not triggering. Adding a console.log(clicks)
at the start of the effect fixes the issue. What am I doing wrong?
Short Circuiting refers to JavaScript's ability to forego the evaluation of other Boolean expressions in a larger expression if the value can be inferred from evaluating the first sub-expressions of said larger expression.
Svelte v5 tracks effect dependencies in runtime. If a reactive value is expected to be read, but it ends up not being read because the expression using it has been discarded due to short-circuiting, then the effect won't record the dependency.
In your case, the expression clicks.length === 2
will not be evaluated (and therefore, value of clicks
won't be read, and therefore the effect will not record it as a dependency) if:
autoDetectSettings.value.mode
is not 'box'
, ORdrawingBox
is falsy.Why? Because all 3 Boolean expressions are being joined with logical AND (&&
). If either of the above is false
, there is no need to continue evaluating the other pieces.
Move clicks.length === 2
to the beginning of the IF statement.
I am blogging about Svelte v5 Reactivity in this series. The next article is half-baked and is about $effect
and things exactly like this one.