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