diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dd0aadf8b..8cdc334868 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased * In `vars` array, correctly indicate whether `module` variables are `mutated` or `reassigned` ([#3215](https://github.com/sveltejs/svelte/issues/3215)) +* Fix spread props not updating in certain situations ([#3521](https://github.com/sveltejs/svelte/issues/3521), [#4480](https://github.com/sveltejs/svelte/issues/4480)) * In `dev` mode, check for unknown props even if the component has no writable props ([#4323](https://github.com/sveltejs/svelte/issues/4323)) * Exclude global variables from `$capture_state` ([#4463](https://github.com/sveltejs/svelte/issues/4463)) * Fix bitmask overflow for slots ([#4481](https://github.com/sveltejs/svelte/issues/4481)) diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 28b3c938f9..8088bbac91 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -224,7 +224,9 @@ export default class InlineComponentWrapper extends Wrapper { const condition = dependencies.size > 0 && (dependencies.size !== all_dependencies.size) ? renderer.dirty(Array.from(dependencies)) : null; + const unchanged = dependencies.size === 0; + let change_object; if (attr.is_spread) { const value = attr.expression.manipulate(block); initial_props.push(value); @@ -233,13 +235,20 @@ export default class InlineComponentWrapper extends Wrapper { if (attr.expression.node.type !== 'ObjectExpression') { value_object = x`@get_spread_object(${value})`; } - changes.push(condition ? x`${condition} && ${value_object}` : value_object); + change_object = value_object; } else { const obj = x`{ ${name}: ${attr.get_value(block)} }`; initial_props.push(obj); - - changes.push(condition ? x`${condition} && ${obj}` : x`${levels}[${i}]`); + change_object = obj; } + + changes.push( + unchanged + ? x`${levels}[${i}]` + : condition + ? x`${condition} && ${change_object}` + : change_object + ); }); block.chunks.init.push(b` diff --git a/test/runtime/samples/spread-component-2/Widget.svelte b/test/runtime/samples/spread-component-2/Widget.svelte new file mode 100644 index 0000000000..ae27aeb5e5 --- /dev/null +++ b/test/runtime/samples/spread-component-2/Widget.svelte @@ -0,0 +1,13 @@ + + +

foo: {foo}

+

baz: {baz} ({typeof baz})

+

qux: {qux}

+

quux: {quux}

+

selected: {selected}

diff --git a/test/runtime/samples/spread-component-2/_config.js b/test/runtime/samples/spread-component-2/_config.js new file mode 100644 index 0000000000..6d36e8e60d --- /dev/null +++ b/test/runtime/samples/spread-component-2/_config.js @@ -0,0 +1,76 @@ +export default { + props: { + list: [{ + foo: 'lol', + baz: 40 + 2, + qux: 5, + quux: 'core' + }, { + foo: 'lolzz', + baz: 50 + 2, + qux: 1, + quux: 'quuxx' + }], + }, + + html: ` +
+

foo: lol

+

baz: 42 (number)

+

qux: 0

+

quux: core

+

selected: true

+

foo: lolzz

+

baz: 52 (number)

+

qux: 0

+

quux: quuxx

+

selected: false

+
+ `, + + test({ assert, component, target }) { + component.list = [{ + foo: 'lol', + baz: 40 + 3, + qux: 8, + quux: 'heart' + }, { + foo: 'lolzz', + baz: 50 + 3, + qux: 8, + quux: 'heartxx' + }]; + + assert.htmlEqual(target.innerHTML, ` +
+

foo: lol

+

baz: 43 (number)

+

qux: 0

+

quux: heart

+

selected: true

+

foo: lolzz

+

baz: 53 (number)

+

qux: 0

+

quux: heartxx

+

selected: false

+
+ `); + + component.qux = 1; + + assert.htmlEqual(target.innerHTML, ` +
+

foo: lol

+

baz: 43 (number)

+

qux: 1

+

quux: heart

+

selected: false

+

foo: lolzz

+

baz: 53 (number)

+

qux: 1

+

quux: heartxx

+

selected: true

+
+ `); + } +}; diff --git a/test/runtime/samples/spread-component-2/main.svelte b/test/runtime/samples/spread-component-2/main.svelte new file mode 100644 index 0000000000..436e11f9c5 --- /dev/null +++ b/test/runtime/samples/spread-component-2/main.svelte @@ -0,0 +1,12 @@ + + +
+ {#each list as item, index (item.foo)} + + {/each} +