Skip to content

Commit 363f4a0

Browse files
trueadmdummdidumm
andauthored
fix: ensure locally mutated bindable props persist with spreading props (#13190)
Fixes #13187. This ensures that we update the local fallback value in the case where the fallback is used so that we persist local changes to bindable props. Otherwise, any incoming changes from the outside will reset the incoming value back to the old fallback value. --------- Co-authored-by: Simon Holthausen <[email protected]>
1 parent 25f67df commit 363f4a0

File tree

5 files changed

+81
-2
lines changed

5 files changed

+81
-2
lines changed

.changeset/fuzzy-tigers-swim.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: ensure locally mutated bindable props persist with spreading props

packages/svelte/src/internal/client/reactivity/props.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,17 @@ export function prop(props, key, flags, fallback) {
238238

239239
var fallback_value = /** @type {V} */ (fallback);
240240
var fallback_dirty = true;
241+
var fallback_used = false;
241242

242243
var get_fallback = () => {
243-
if (lazy && fallback_dirty) {
244+
fallback_used = true;
245+
if (fallback_dirty) {
244246
fallback_dirty = false;
245-
fallback_value = untrack(/** @type {() => V} */ (fallback));
247+
if (lazy) {
248+
fallback_value = untrack(/** @type {() => V} */ (fallback));
249+
} else {
250+
fallback_value = /** @type {V} */ (fallback);
251+
}
246252
}
247253

248254
return fallback_value;
@@ -264,6 +270,7 @@ export function prop(props, key, flags, fallback) {
264270
var value = /** @type {V} */ (props[key]);
265271
if (value === undefined) return get_fallback();
266272
fallback_dirty = true;
273+
fallback_used = false;
267274
return value;
268275
};
269276
} else {
@@ -351,6 +358,11 @@ export function prop(props, key, flags, fallback) {
351358
if (!current_value.equals(new_value)) {
352359
from_child = true;
353360
set(inner_current_value, new_value);
361+
// To ensure the fallback value is consistent when used with proxies, we
362+
// update the local fallback_value, but only if the fallback is actively used
363+
if (fallback_used && fallback_value !== undefined) {
364+
fallback_value = new_value;
365+
}
354366
get(current_value); // force a synchronisation immediately
355367
}
356368

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
accessors: false,
6+
7+
test({ assert, target }) {
8+
const [btn1, btn2] = target.querySelectorAll('button');
9+
10+
btn1.click();
11+
flushSync();
12+
assert.htmlEqual(
13+
target.innerHTML,
14+
`<button>set color</button> <button>set options</button> bar bar`
15+
);
16+
17+
btn2.click();
18+
flushSync();
19+
assert.htmlEqual(
20+
target.innerHTML,
21+
`<button>set color</button> <button>set options</button> baz bar`
22+
);
23+
24+
btn1.click();
25+
flushSync();
26+
assert.htmlEqual(
27+
target.innerHTML,
28+
`<button>set color</button> <button>set options</button> foo bar`
29+
);
30+
}
31+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
let { options = $bindable('foo') } = $props();
3+
4+
options = 'bar'
5+
</script>
6+
7+
{options}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script >
2+
import Inner from "./inner.svelte";
3+
4+
let testProps = $state({
5+
color: "red"
6+
});
7+
</script>
8+
9+
<button onclick={() => {
10+
testProps = {
11+
color: "blue"
12+
};
13+
}}>set color</button>
14+
15+
<button onclick={() => {
16+
testProps = {
17+
color: "pink",
18+
options: 'baz'
19+
};
20+
}}>set options</button>
21+
22+
<Inner {...testProps} />
23+
24+
<Inner color={testProps.color} />

0 commit comments

Comments
 (0)