diff --git a/.changeset/khaki-carrots-mix.md b/.changeset/khaki-carrots-mix.md new file mode 100644 index 0000000000..13f7b90cb9 --- /dev/null +++ b/.changeset/khaki-carrots-mix.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure legacy props cache last value when destroyed diff --git a/packages/svelte/src/internal/client/reactivity/props.js b/packages/svelte/src/internal/client/reactivity/props.js index eec8e70dc6..0cb5d3bd9d 100644 --- a/packages/svelte/src/internal/client/reactivity/props.js +++ b/packages/svelte/src/internal/client/reactivity/props.js @@ -324,12 +324,23 @@ export function prop(props, key, flags, fallback) { } else { // Svelte 4 did not trigger updates when a primitive value was updated to the same value. // Replicate that behavior through using a derived - var derived_getter = with_parent_branch(() => - (immutable ? derived : derived_safe_equal)(() => /** @type {V} */ (props[key])) - ); + var derived_getter = with_parent_branch(() => { + return (immutable ? derived : derived_safe_equal)(() => /** @type {V} */ (props[key])); + }); + // Connect the derived getter to the parent branch effect + get(derived_getter); + derived_getter.f |= LEGACY_DERIVED_PROP; + /** @type {V} */ + var last_value; + getter = () => { + // Emulate the Svelte 4 behaviour of returning the last known value + if ((derived_getter.f & DESTROYED) !== 0) { + return last_value; + } var value = get(derived_getter); + last_value = value; if (value !== undefined) fallback_value = /** @type {V} */ (undefined); return value === undefined ? fallback_value : value; }; diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/Child.svelte new file mode 100644 index 0000000000..2051517eaf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/Child.svelte @@ -0,0 +1,9 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/_config.js b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/_config.js new file mode 100644 index 0000000000..363c850c8b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/_config.js @@ -0,0 +1,10 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, logs, target }) { + target.querySelector('button')?.click(); + flushSync(); + assert.deepEqual(logs, ['should fire once']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/main.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/main.svelte new file mode 100644 index 0000000000..00c6a5f71c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/main.svelte @@ -0,0 +1,17 @@ + + + + +{#if active} + +{/if} \ No newline at end of file