diff --git a/.changeset/dirty-worms-type.md b/.changeset/dirty-worms-type.md new file mode 100644 index 000000000000..0a824fcb1d90 --- /dev/null +++ b/.changeset/dirty-worms-type.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: avoid disconnecting deriveds that are still active diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index bfea047b24ef..3c28c6ca8a6d 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -370,7 +370,14 @@ function remove_reaction(signal, dependency) { } // If the derived has no reactions, then we can disconnect it from the graph, // allowing it to either reconnect in the future, or be GC'd by the VM. - if (reactions === null && (dependency.f & DERIVED) !== 0) { + if ( + reactions === null && + (dependency.f & DERIVED) !== 0 && + // Destroying a child effect while updating a parent effect can cause a dependency to appear + // to be unused, when in fact it is used by the currently-updating parent. Checking `new_deps` + // allows us to skip the expensive work of disconnecting and immediately reconnecting it + (new_deps === null || !new_deps.includes(dependency)) + ) { set_signal_status(dependency, MAYBE_DIRTY); // If we are working with a derived that is owned by an effect, then mark it as being // disconnected. diff --git a/packages/svelte/tests/runtime-runes/samples/if-block-dependencies/_config.js b/packages/svelte/tests/runtime-runes/samples/if-block-dependencies/_config.js new file mode 100644 index 000000000000..b5847f3f7b63 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/if-block-dependencies/_config.js @@ -0,0 +1,19 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await Promise.resolve(); + + let [btn1] = target.querySelectorAll('button'); + + flushSync(() => { + btn1?.click(); + }); + + assert.htmlEqual( + target.innerHTML, + `false\ntrue\n\nfirst:\nfalse\n
\nsecond:\ntrue` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/if-block-dependencies/main.svelte b/packages/svelte/tests/runtime-runes/samples/if-block-dependencies/main.svelte new file mode 100644 index 000000000000..72f435d91de2 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/if-block-dependencies/main.svelte @@ -0,0 +1,21 @@ + + +{first} {second} + + + +{#if first || derivedSecond} + first: {first} +
+ second: {derivedSecond} +{/if}