fix: ensure eager effects don't break reactions chain (#17138)

Execution of eager effects didn't set `is_updating_effect`, which meant the logic in `get` would wrongfully prevent dependencies being added to `reactions` of sources/deriveds.

Fixes #17133
pull/17168/head
Simon H 2 days ago committed by GitHub
parent a7a6d898d5
commit 99e670f632
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ensure eager effects don't break reactions chain

@ -14,7 +14,9 @@ import {
is_dirty,
untracking,
is_destroying_effect,
push_reaction_value
push_reaction_value,
set_is_updating_effect,
is_updating_effect
} from '../runtime.js';
import { equals, safe_equals } from './equality.js';
import {
@ -246,19 +248,25 @@ export function internal_set(source, value) {
export function flush_eager_effects() {
eager_effects_deferred = false;
var prev_is_updating_effect = is_updating_effect;
set_is_updating_effect(true);
const inspects = Array.from(eager_effects);
for (const effect of inspects) {
// Mark clean inspect-effects as maybe dirty and then check their dirtiness
// instead of just updating the effects - this way we avoid overfiring.
if ((effect.f & CLEAN) !== 0) {
set_signal_status(effect, MAYBE_DIRTY);
}
try {
for (const effect of inspects) {
// Mark clean inspect-effects as maybe dirty and then check their dirtiness
// instead of just updating the effects - this way we avoid overfiring.
if ((effect.f & CLEAN) !== 0) {
set_signal_status(effect, MAYBE_DIRTY);
}
if (is_dirty(effect)) {
update_effect(effect);
if (is_dirty(effect)) {
update_effect(effect);
}
}
} finally {
set_is_updating_effect(prev_is_updating_effect);
}
eager_effects.clear();

@ -0,0 +1,35 @@
import { tick } from 'svelte';
import { test } from '../../test';
import { normalise_inspect_logs } from '../../../helpers';
export default test({
compileOptions: {
dev: true
},
async test({ assert, target, logs }) {
const [b] = target.querySelectorAll('button');
b.click();
await tick();
assert.htmlEqual(target.innerHTML, `<button>first unseen: 1</button>`);
b.click();
await tick();
assert.htmlEqual(target.innerHTML, `<button>first unseen: 2</button>`);
b.click();
await tick();
assert.htmlEqual(target.innerHTML, `<button>first unseen:</button>`);
assert.deepEqual(normalise_inspect_logs(logs), [
[0, 1, 2],
[1, 2],
'at SvelteSet.add',
[2],
'at SvelteSet.add',
[],
'at SvelteSet.add'
]);
}
});

@ -0,0 +1,14 @@
<script>
import {SvelteSet} from "svelte/reactivity";
const ids = [0,1,2];
const seenIds = new SvelteSet();
const unseenIds = $derived(ids.filter((id) => !seenIds.has(id)));
const currentId = $derived(unseenIds.at(0));
$inspect(unseenIds)
</script>
<button onclick={() => seenIds.add(currentId)}>
first unseen: {currentId}
</button>
Loading…
Cancel
Save