fix: don't destroy effect roots created inside of deriveds

We were wrongfully adding effect roots to `derived.effects`, too, which meant those were destroyed when the derived reran.
pull/16492/head
Simon Holthausen 1 month ago
parent 4e74cd35fe
commit 7f5042475f

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: don't destroy effect roots created inside of deriveds

@ -148,7 +148,11 @@ function create_effect(type, fn, sync, push = true) {
}
// if we're in a derived, add the effect there too
if (active_reaction !== null && (active_reaction.f & DERIVED) !== 0) {
if (
active_reaction !== null &&
(active_reaction.f & DERIVED) !== 0 &&
(type & ROOT_EFFECT) === 0
) {
var derived = /** @type {Derived} */ (active_reaction);
(derived.effects ??= []).push(effect);
}

@ -54,7 +54,7 @@ export interface Reaction extends Signal {
export interface Derived<V = unknown> extends Value<V>, Reaction {
/** The derived function */
fn: () => V;
/** Effects created inside this signal */
/** Effects created inside this signal. Used to destroy those effects when the derived reruns or is cleaned up */
effects: null | Effect[];
/** Parent effect or derived */
parent: Effect | Derived | null;

@ -1390,4 +1390,55 @@ describe('signals', () => {
destroy();
};
});
test('$effect.root inside deriveds stay alive independently', () => {
const log: any[] = [];
const c = state(0);
const cleanup: any[] = [];
const inner_states: any[] = [];
const d = derived(() => {
const destroy = effect_root(() => {
const x = state(0);
inner_states.push(x);
effect(() => {
log.push('inner ' + $.get(x));
return () => {
log.push('inner destroyed');
};
});
});
cleanup.push(destroy);
return $.get(c);
});
return () => {
log.push($.get(d));
flushSync();
assert.deepEqual(log, [0, 'inner 0']);
log.length = 0;
set(inner_states[0], 1);
flushSync();
assert.deepEqual(log, ['inner destroyed', 'inner 1']);
log.length = 0;
set(c, 1);
log.push($.get(d));
flushSync();
assert.deepEqual(log, [1, 'inner 0']);
log.length = 0;
cleanup.forEach((fn) => fn());
flushSync();
assert.deepEqual(log, ['inner destroyed', 'inner destroyed']);
};
});
});

Loading…
Cancel
Save