diff --git a/.changeset/rare-worms-hunt.md b/.changeset/rare-worms-hunt.md new file mode 100644 index 000000000000..e0963bd6af21 --- /dev/null +++ b/.changeset/rare-worms-hunt.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: only update lazy properties that have actually changed diff --git a/packages/svelte/src/internal/client/each.js b/packages/svelte/src/internal/client/each.js index 032edad201b0..8485f519582e 100644 --- a/packages/svelte/src/internal/client/each.js +++ b/packages/svelte/src/internal/client/each.js @@ -786,10 +786,20 @@ export function get_first_element(block) { * @returns {void} */ function update_each_item_block(block, item, index, type) { + const block_v = block.v; if ((type & EACH_ITEM_REACTIVE) !== 0) { - set_signal_value(block.v, item); - } else if (is_lazy_property(block.v)) { - block.v.o[block.v.p] = item; + set_signal_value(block_v, item); + } else if (is_lazy_property(block_v)) { + // If we have lazy properties, it means that an array was used that has been + // proxied. Given this, we need to re-sync the old array by mutating the backing + // value to be the latest value to ensure the UI updates correctly. TODO: maybe + // we should bypass any internal mutation checks for this? + const o = block_v.o; + const p = block_v.p; + const prev = o[p]; + if (prev !== item) { + o[p] = item; + } } const transitions = block.s; const index_is_reactive = (type & EACH_INDEX_REACTIVE) !== 0; diff --git a/packages/svelte/tests/runtime-runes/samples/readonly-state-push/Child.svelte b/packages/svelte/tests/runtime-runes/samples/readonly-state-push/Child.svelte new file mode 100644 index 000000000000..dc79fc19bf58 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/readonly-state-push/Child.svelte @@ -0,0 +1,7 @@ + + +{#each array as number} +
{number}
+{/each} diff --git a/packages/svelte/tests/runtime-runes/samples/readonly-state-push/_config.js b/packages/svelte/tests/runtime-runes/samples/readonly-state-push/_config.js new file mode 100644 index 000000000000..3d3895312722 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/readonly-state-push/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [b1] = target.querySelectorAll('button'); + b1.click(); + await Promise.resolve(); + + assert.htmlEqual( + target.innerHTML, + '1
2
3
4
0
' + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/readonly-state-push/main.svelte b/packages/svelte/tests/runtime-runes/samples/readonly-state-push/main.svelte new file mode 100644 index 000000000000..51c0940b9793 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/readonly-state-push/main.svelte @@ -0,0 +1,13 @@ + + + +