fix: ensure unowned deriveds can add themselves as reactions while connected (#16249)

an unowned derived should still add itself as a reaction while it is properly connected, which means it can be cleaned up correctly - and this connection is indicated by it having reactions.

Fixes #15829 and potentially #15853
pull/16257/head
Simon H 2 months ago committed by GitHub
parent 32481bece6
commit 7019894fd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ensure unowned deriveds can add themselves as reactions while connected

@ -294,7 +294,12 @@ export function update_reaction(reaction) {
reaction.deps = deps = new_deps;
}
if (!skip_reaction) {
if (
!skip_reaction ||
// Deriveds that already have reactions can cleanup, so we still add them as reactions
((flags & DERIVED) !== 0 &&
/** @type {import('#client').Derived} */ (reaction).reactions !== null)
) {
for (i = skipped_deps; i < deps.length; i++) {
(deps[i].reactions ??= []).push(reaction);
}

@ -112,6 +112,45 @@ describe('signals', () => {
};
});
test('unowned deriveds are not added as reactions but trigger effects', () => {
var obj = state<any>(undefined);
class C1 {
#v = state(0);
get v() {
return $.get(this.#v);
}
set v(v: number) {
set(this.#v, v);
}
}
return () => {
let d = derived(() => $.get(obj)?.v || '-');
const log: number[] = [];
assert.equal($.get(d), '-');
let destroy = effect_root(() => {
render_effect(() => {
log.push($.get(d));
});
});
set(obj, new C1());
flushSync();
assert.equal($.get(d), '-');
$.get(obj).v = 1;
flushSync();
assert.equal($.get(d), 1);
assert.deepEqual(log, ['-', 1]);
destroy();
// ensure we're not leaking reactions
assert.equal(obj.reactions, null);
assert.equal(d.reactions, null);
};
});
test('derived from state', () => {
const log: number[] = [];

Loading…
Cancel
Save