diff --git a/.changeset/fix-derived-teardown-eager-path.md b/.changeset/fix-derived-teardown-eager-path.md new file mode 100644 index 0000000000..a781ee2f27 --- /dev/null +++ b/.changeset/fix-derived-teardown-eager-path.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: ensure `$derived` returns pre-change value during teardown in eager block effects path diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 7d14b80519..8d58c5c830 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -1111,8 +1111,6 @@ function flush_queued_effects(effects) { // If update_effect() has a flushSync() in it, we may have flushed another flush_queued_effects(), // which already handled this logic and did set eager_block_effects to null. if (eager_block_effects?.size > 0) { - old_values.clear(); - for (const e of eager_block_effects) { // Skip eager effects that have already been unmounted if ((e.f & (DESTROYED | INERT)) !== 0) continue; diff --git a/packages/svelte/tests/runtime-runes/samples/derived-old-value-eager-unmount/Child.svelte b/packages/svelte/tests/runtime-runes/samples/derived-old-value-eager-unmount/Child.svelte new file mode 100644 index 0000000000..551a75855a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-old-value-eager-unmount/Child.svelte @@ -0,0 +1,25 @@ + + +a: {a} +b: {b} +c: {c} +d: {d} diff --git a/packages/svelte/tests/runtime-runes/samples/derived-old-value-eager-unmount/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-old-value-eager-unmount/_config.js new file mode 100644 index 0000000000..9433ded65c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-old-value-eager-unmount/_config.js @@ -0,0 +1,14 @@ +import { flushSync } from 'svelte'; +import { test, ok } from '../../test'; + +export default test({ + async test({ assert, logs, target }) { + const button = target.querySelector('button'); + ok(button); + + flushSync(() => button.click()); + + // All four teardowns should see the pre-change derived value (2), not the post-change value (10) + assert.deepEqual(logs, ['effect.pre', 2, 'attach', 2, 'effect', 2, 'onDestroy', 2]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-old-value-eager-unmount/main.svelte b/packages/svelte/tests/runtime-runes/samples/derived-old-value-eager-unmount/main.svelte new file mode 100644 index 0000000000..19c52409ed --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-old-value-eager-unmount/main.svelte @@ -0,0 +1,17 @@ + + + + +{#if count < 5} + +{/if} diff --git a/packages/svelte/tests/runtime-runes/samples/onmount-prop-access/_config.js b/packages/svelte/tests/runtime-runes/samples/onmount-prop-access/_config.js index 0d24e265d3..a7727343eb 100644 --- a/packages/svelte/tests/runtime-runes/samples/onmount-prop-access/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/onmount-prop-access/_config.js @@ -2,6 +2,6 @@ import { test } from '../../test'; export default test({ async test({ assert, logs }) { - assert.deepEqual(logs, [1]); + assert.deepEqual(logs, [0]); } });