fix: improve key block reactivity detection (#10092)

pull/10070/head
Dominic Gannaway 10 months ago committed by GitHub
parent 86eae7e77d
commit ddd7926240
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve key block reactivity detection

@ -1,6 +1,7 @@
export const EACH_ITEM_REACTIVE = 1; export const EACH_ITEM_REACTIVE = 1;
export const EACH_INDEX_REACTIVE = 1 << 1; export const EACH_INDEX_REACTIVE = 1 << 1;
export const EACH_KEYED = 1 << 2; export const EACH_KEYED = 1 << 2;
export const EACH_PROXIED = 1 << 3;
export const EACH_IS_CONTROLLED = 1 << 3; export const EACH_IS_CONTROLLED = 1 << 3;
export const EACH_IS_ANIMATED = 1 << 4; export const EACH_IS_ANIMATED = 1 << 4;
export const EACH_IS_IMMUTABLE = 1 << 6; export const EACH_IS_IMMUTABLE = 1 << 6;

@ -351,13 +351,8 @@ function reconcile_tracked_array(
) { ) {
var a_blocks = each_block.v; var a_blocks = each_block.v;
const is_computed_key = keys !== null; const is_computed_key = keys !== null;
var is_proxied_array = STATE_SYMBOL in array && /** @type {any} */ (array[STATE_SYMBOL]).i;
var active_transitions = each_block.s; var active_transitions = each_block.s;
if (is_proxied_array) {
flags &= ~EACH_ITEM_REACTIVE;
}
/** @type {number | void} */ /** @type {number | void} */
var a = a_blocks.length; var a = a_blocks.length;

@ -0,0 +1,39 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
html: `<p>test costs $1</p><p>test 2 costs $2</p><p>test costs $1</p><p>test 2 costs $2</p><button>add</button><button>change</button><button>reload</button>`,
skip_if_ssr: 'permanent',
skip_if_hydrate: 'permanent',
async test({ assert, target }) {
const [btn1, btn2, btn3] = target.querySelectorAll('button');
flushSync(() => {
btn2.click();
});
assert.htmlEqual(
target.innerHTML,
`<p>test costs $1</p><p>test 2 costs $2000</p><p>test costs $1</p><p>test 2 costs $2000</p><button>add</button><button>change</button><button>reload</button>`
);
flushSync(() => {
btn1.click();
});
assert.htmlEqual(
target.innerHTML,
`<p>test costs $1</p><p>test 2 costs $2000</p><p>test 3 costs $3</p><p>test costs $1</p><p>test 2 costs $2000</p><p>test 3 costs $3</p><button>add</button><button>change</button><button>reload</button>`
);
flushSync(() => {
btn3.click();
});
assert.htmlEqual(
target.innerHTML,
`<p>test costs $1</p><p>test 2 costs $2000</p><p>test costs $1</p><p>test 2 costs $2000</p><button>add</button><button>change</button><button>reload</button>`
);
}
});

@ -0,0 +1,54 @@
<script>
let data = $state({ items: [] });
function fetchData() {
data = {
items: [{
id: 1,
price: 1,
name: 'test'
}, {
id: 2,
price: 2,
name: 'test 2'
}]
};
}
fetchData();
function copyItems(original) {
return [...original.map((item) => ({ ...item }))];
}
let items = $state();
$effect(() => {
items = copyItems(data.items);
});
</script>
{#each items as item}
<p>{item.name} costs ${item.price}</p>
{/each}
{#each items as item (item.id)}
<p>{item.name} costs ${item.price}</p>
{/each}
<button onclick={() => {
items.push({
id: 3,
price: 3,
name: 'test 3'
})
}}>add</button>
<button onclick={() => {
data.items[1].price = 2000
}}>change</button>
<button onclick={() => {
fetchData();
}}>reload</button>
Loading…
Cancel
Save