From 210d127deb8a3a43820511c498c7b83d72fcd906 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 24 May 2025 16:25:22 -0400 Subject: [PATCH] fix: don't mark deriveds as clean if updating during teardown --- .changeset/old-insects-divide.md | 5 +++++ .../internal/client/reactivity/deriveds.js | 16 +++++++++----- .../effect-teardown-stale-value/_config.js | 22 +++++++++++++++++++ .../effect-teardown-stale-value/main.svelte | 14 ++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 .changeset/old-insects-divide.md create mode 100644 packages/svelte/tests/runtime-runes/samples/effect-teardown-stale-value/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/effect-teardown-stale-value/main.svelte diff --git a/.changeset/old-insects-divide.md b/.changeset/old-insects-divide.md new file mode 100644 index 0000000000..75707eb428 --- /dev/null +++ b/.changeset/old-insects-divide.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: don't mark deriveds as clean if updating during teardown diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index 21780be862..e9cea0df3e 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -9,7 +9,8 @@ import { update_reaction, increment_write_version, set_active_effect, - push_reaction_value + push_reaction_value, + is_destroying_effect } from '../runtime.js'; import { equals, safe_equals } from './equality.js'; import * as e from '../errors.js'; @@ -172,13 +173,18 @@ export function execute_derived(derived) { */ export function update_derived(derived) { var value = execute_derived(derived); - var status = - (skip_reaction || (derived.f & UNOWNED) !== 0) && derived.deps !== null ? MAYBE_DIRTY : CLEAN; - - set_signal_status(derived, status); if (!derived.equals(value)) { derived.v = value; derived.wv = increment_write_version(); } + + // don't mark derived clean if we're reading it inside a + // cleanup function, or it will cache a stale value + if (is_destroying_effect) return; + + var status = + (skip_reaction || (derived.f & UNOWNED) !== 0) && derived.deps !== null ? MAYBE_DIRTY : CLEAN; + + set_signal_status(derived, status); } diff --git a/packages/svelte/tests/runtime-runes/samples/effect-teardown-stale-value/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-teardown-stale-value/_config.js new file mode 100644 index 0000000000..1016ffb43e --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-teardown-stale-value/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + html: ``, + + async test({ assert, target, logs }) { + assert.deepEqual(logs, ['up', { foo: false, bar: false }]); + + const button = target.querySelector('button'); + + flushSync(() => button?.click()); + assert.deepEqual(logs, [ + 'up', + { foo: false, bar: false }, + 'down', + { foo: false, bar: false }, + 'up', + { foo: true, bar: true } + ]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-teardown-stale-value/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-teardown-stale-value/main.svelte new file mode 100644 index 0000000000..fff81591d5 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-teardown-stale-value/main.svelte @@ -0,0 +1,14 @@ + + +