fix: ensure bind:this unmount behavior for members is conditional (#11193)

* fix: ensure bind:this unmount behavior for members is conditional

* revise
pull/11196/head
Dominic Gannaway 1 year ago committed by GitHub
parent e7869faf4d
commit 77ed790fb3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: ensure bind:this unmount behavior for members is conditional

@ -917,6 +917,15 @@ function serialize_bind_this(bind_this, context, node) {
/** @type {import('estree').Expression[]} */ /** @type {import('estree').Expression[]} */
const args = [node, b.arrow([b.id('$$value'), ...ids], update), b.arrow([...ids], bind_this_id)]; const args = [node, b.arrow([b.id('$$value'), ...ids], update), b.arrow([...ids], bind_this_id)];
// If we're mutating a property, then it might already be non-existent.
// If we make all the object nodes optional, then it avoids any runtime exceptions.
/** @type {import('estree').Expression | import('estree').Super} */
let bind_node = bind_this_id;
while (bind_node?.type === 'MemberExpression') {
bind_node.optional = true;
bind_node = bind_node.object;
}
if (each_ids.size) { if (each_ids.size) {
args.push(b.thunk(b.array(Array.from(each_ids.values()).map((id) => id[1])))); args.push(b.thunk(b.array(Array.from(each_ids.values()).map((id) => id[1]))));
} }

@ -0,0 +1,7 @@
<script>
let { item = $bindable() } = $props();
</script>
<div bind:this={item.dom}>
{item.text}
</div>

@ -0,0 +1,25 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target, component }) {
const [b1, b2] = target.querySelectorAll('button');
flushSync(() => {
b1.click();
b1.click();
b1.click();
});
assert.htmlEqual(
target.innerHTML,
`<button>add item</button><button>clear</button><div>Item 1</div><div>Item 2</div><div>Item 3</div>`
);
flushSync(() => {
b2.click();
});
assert.htmlEqual(target.innerHTML, `<button>add item</button><button>clear</button>`);
}
});

@ -0,0 +1,23 @@
<script>
import Child from './Child.svelte';
let items = $state([]);
function add_item() {
items.push({
id: items.length,
text: 'Item ' + (items.length + 1),
dom: null,
})
}
function clear() {
items = [];
}
</script>
<button on:click={add_item}>add item</button>
<button on:click={clear}>clear</button>
{#each items as item, index (item.id)}
<Child bind:item={items[index]} />
{/each}
Loading…
Cancel
Save