pull/18424/merge
spokodev 7 days ago committed by GitHub
commit 54873d2039
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: do not connect dependencies of an unconnected derived during init-time reads

@ -660,12 +660,19 @@ export function get(signal) {
}
// connect disconnected deriveds if we are reading them inside an effect,
// or inside another derived that is already connected
// or inside another derived that is already connected. A derived reader
// that is itself unconnected must not connect its dependencies, even
// while an effect update is in progress (e.g. an init-time prop read
// evaluating a parent prop-expression memo): the dependency would be
// subscribed into the graph while nothing subscribes to the reader, so
// no destroy cascade could ever reach it (#18420)
var should_connect =
(derived.f & CONNECTED) === 0 &&
!untracking &&
active_reaction !== null &&
(is_updating_effect || (active_reaction.f & CONNECTED) !== 0);
((active_reaction.f & DERIVED) !== 0
? (active_reaction.f & CONNECTED) !== 0
: is_updating_effect || (active_reaction.f & CONNECTED) !== 0);
var is_new = (derived.f & REACTION_RAN) === 0;

@ -3,6 +3,7 @@ import { flushSync } from '../../src/index-client';
import * as $ from '../../src/internal/client/runtime';
import { push, pop } from '../../src/internal/client/context';
import {
branch,
effect,
effect_root,
render_effect,
@ -1503,4 +1504,52 @@ describe('signals', () => {
assert.deepEqual(log, ['inner destroyed', 'inner destroyed']);
};
});
// https://github.com/sveltejs/svelte/issues/18420
test('init-time read of an unconnected derived does not zombie-connect its dependencies', () => {
const s = state(0);
const inner = derived(() => $.get(s));
const memo = derived(() => $.get(inner));
return () => {
// mirrors a component's init-time prop read (e.g. a prop default):
// a branch effect body runs with `active_reaction === null` while an
// effect update is in progress, and the read evaluates the parent's
// prop-expression memo unconnected
const destroy = effect_root(() => {
branch(() => {
assert.equal($.get(memo), 0);
});
});
destroy();
// `inner` must not stay subscribed to `s` — nothing holds a
// reference to `inner` that a destroy cascade could reach
assert.equal(s.reactions, null);
assert.equal(inner.reactions, null);
};
});
// https://github.com/sveltejs/svelte/issues/18420
test('connected read of the same derived chain still cleans up on destroy', () => {
const s = state(0);
const inner = derived(() => $.get(s));
const memo = derived(() => $.get(inner));
return () => {
const destroy = effect_root(() => {
branch(() => {
render_effect(() => {
assert.equal($.get(memo), 0);
});
});
});
flushSync();
destroy();
assert.equal(s.reactions, null);
};
});
});

Loading…
Cancel
Save