diff --git a/packages/svelte/src/internal/client/reactivity/props.js b/packages/svelte/src/internal/client/reactivity/props.js index ee07a342a8..33f0e67a6d 100644 --- a/packages/svelte/src/internal/client/reactivity/props.js +++ b/packages/svelte/src/internal/client/reactivity/props.js @@ -12,7 +12,7 @@ import { import { get_descriptor, is_function } from '../../shared/utils.js'; import { set, source, update } from './sources.js'; import { derived, derived_safe_equal } from './deriveds.js'; -import { get, untrack } from '../runtime.js'; +import { get, is_destroying_effect, untrack } from '../runtime.js'; import * as e from '../errors.js'; import { LEGACY_PROPS, STATE_SYMBOL } from '#client/constants'; import { proxy } from '../proxy.js'; @@ -366,7 +366,12 @@ export function prop(props, key, flags, fallback) { // prop is written to, but there's no binding, which means we // create a derived that we can write to locally - var d = ((flags & PROPS_IS_IMMUTABLE) !== 0 ? derived : derived_safe_equal)(getter); + var overridden = false; + + var d = ((flags & PROPS_IS_IMMUTABLE) !== 0 ? derived : derived_safe_equal)(() => { + overridden = false; + return getter(); + }); // Capture the initial value if it's bindable if (bindable) get(d); @@ -376,6 +381,7 @@ export function prop(props, key, flags, fallback) { const new_value = mutation ? get(d) : runes && bindable ? proxy(value) : value; set(d, new_value); + overridden = true; if (fallback_value !== undefined) { fallback_value = new_value; @@ -384,7 +390,10 @@ export function prop(props, key, flags, fallback) { return value; } - if (has_destroyed_component_ctx(d)) { + // special case — avoid recalculating the derived if + // we're in a teardown function and the prop + // was overridden locally + if (is_destroying_effect && overridden) { return d.v; } diff --git a/packages/svelte/tests/runtime-runes/samples/effect-teardown-derived/Component.svelte b/packages/svelte/tests/runtime-runes/samples/effect-teardown-derived/Component.svelte new file mode 100644 index 0000000000..3c863c7fc9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-teardown-derived/Component.svelte @@ -0,0 +1,15 @@ + + +

{count}

+ + + diff --git a/packages/svelte/tests/runtime-runes/samples/effect-teardown-derived/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-teardown-derived/_config.js new file mode 100644 index 0000000000..1f6e5d1f7f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-teardown-derived/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + async test({ assert, target, logs }) { + const [increment, toggle] = target.querySelectorAll('button'); + + flushSync(() => toggle.click()); + assert.deepEqual(logs, [0, 'hello']); + + flushSync(() => toggle.click()); + flushSync(() => increment.click()); + flushSync(() => increment.click()); + + assert.deepEqual(logs, [0, 'hello', 1, 'hello']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-teardown-derived/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-teardown-derived/main.svelte new file mode 100644 index 0000000000..1a97d3e760 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-teardown-derived/main.svelte @@ -0,0 +1,13 @@ + + + + + +{#if count < 2 && message === 'hello'} + +{/if}