From f9f5d3a1be8a77832c07c8d06002ee971791371e Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 6 Feb 2024 16:33:55 +0000 Subject: [PATCH] fix: only update lazy properties that have actually changed (#10415) * fix: only update lazy properties that have actually changed * code golf * changeset * Add test --- .changeset/rare-worms-hunt.md | 5 +++++ packages/svelte/src/internal/client/each.js | 16 +++++++++++++--- .../samples/readonly-state-push/Child.svelte | 7 +++++++ .../samples/readonly-state-push/_config.js | 14 ++++++++++++++ .../samples/readonly-state-push/main.svelte | 13 +++++++++++++ 5 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 .changeset/rare-worms-hunt.md create mode 100644 packages/svelte/tests/runtime-runes/samples/readonly-state-push/Child.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/readonly-state-push/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/readonly-state-push/main.svelte diff --git a/.changeset/rare-worms-hunt.md b/.changeset/rare-worms-hunt.md new file mode 100644 index 0000000000..e0963bd6af --- /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 032edad201..8485f51958 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 0000000000..dc79fc19bf --- /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 0000000000..3d38953127 --- /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 0000000000..51c0940b97 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/readonly-state-push/main.svelte @@ -0,0 +1,13 @@ + + + + +