Skip to content

Commit 4a8f0bc

Browse files
authored
fix: keep fallback value after spread update not setting that prop (#9717)
fixes #9716
1 parent 65fa717 commit 4a8f0bc

File tree

5 files changed

+85
-1
lines changed

5 files changed

+85
-1
lines changed

.changeset/ninety-dingos-walk.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: keep fallback value after spread update not setting that prop

packages/svelte/src/internal/client/runtime.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,7 @@ export function prop_source(props_obj, key, default_value, call_default_value) {
14301430
.i;
14311431
let ignore_next1 = false;
14321432
let ignore_next2 = false;
1433+
let did_update_to_defined = !should_set_default_value;
14331434

14341435
let mount = true;
14351436
sync_effect(() => {
@@ -1445,8 +1446,13 @@ export function prop_source(props_obj, key, default_value, call_default_value) {
14451446
return;
14461447
}
14471448

1448-
if (not_equal(immutable, propagating_value, source_signal.v)) {
1449+
if (
1450+
// Ensure that updates from undefined to undefined are ignored
1451+
(did_update_to_defined || propagating_value !== undefined) &&
1452+
not_equal(immutable, propagating_value, source_signal.v)
1453+
) {
14491454
ignore_next2 = true;
1455+
did_update_to_defined = true;
14501456
// TODO figure out why we need it this way and the explain in a comment;
14511457
// some tests fail is we just do set_signal_value(source_signal, propagating_value)
14521458
untrack(() => set_signal_value(source_signal, propagating_value));
@@ -1469,6 +1475,7 @@ export function prop_source(props_obj, key, default_value, call_default_value) {
14691475

14701476
if (not_equal(immutable, propagating_value, possible_signal.v)) {
14711477
ignore_next1 = true;
1478+
did_update_to_defined = true;
14721479
untrack(() => update_bound_prop(propagating_value));
14731480
}
14741481
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
const { propA, propB = "fallback" } = $props();
3+
</script>
4+
5+
<p>{propA} {propB}</p>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { test } from '../../test';
2+
3+
// Tests that fallback values are kept as long as the prop is not defined in the case of a spread
4+
export default test({
5+
accessors: false, // so that propA actually becomes $.prop and not $.prop_source
6+
html: `
7+
<button>change propA</button>
8+
<button>change propB</button>
9+
<p>true fallback</p>
10+
`,
11+
12+
async test({ assert, target }) {
13+
const [propA, propB] = target.querySelectorAll('button');
14+
15+
await propA.click();
16+
assert.htmlEqual(
17+
target.innerHTML,
18+
`
19+
<button>change propA</button>
20+
<button>change propB</button>
21+
<p>false fallback</p>
22+
`
23+
);
24+
25+
await propB.click();
26+
assert.htmlEqual(
27+
target.innerHTML,
28+
`
29+
<button>change propA</button>
30+
<button>change propB</button>
31+
<p>false defined</p>
32+
`
33+
);
34+
35+
await propA.click();
36+
assert.htmlEqual(
37+
target.innerHTML,
38+
`
39+
<button>change propA</button>
40+
<button>change propB</button>
41+
<p>true defined</p>
42+
`
43+
);
44+
45+
await propB.click();
46+
assert.htmlEqual(
47+
target.innerHTML,
48+
`
49+
<button>change propA</button>
50+
<button>change propB</button>
51+
<p>true</p>
52+
`
53+
);
54+
}
55+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script>
2+
import Component from './Component.svelte';
3+
4+
let props = $state({
5+
propA: true,
6+
propB: undefined
7+
});
8+
</script>
9+
10+
<button on:click={() => {props.propA = !props.propA}}>change propA</button>
11+
<button on:click={() => {props.propB = props.propB ? undefined : 'defined'}}>change propB</button>
12+
<Component {...props}/>

0 commit comments

Comments
 (0)