fix: always synchronously call `bind:this` (#12679)

fixes #12673

#12591 wrongfully applied the "wrap in effect if an action on this element" logic for `bind:this`
pull/12680/head
Simon H 5 months ago committed by GitHub
parent ccccac394b
commit 01e7845180
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: always synchronously call `bind:this`

@ -3164,16 +3164,15 @@ export const template_visitors = {
} }
const parent = /** @type {import('#compiler').SvelteNode} */ (context.path.at(-1)); const parent = /** @type {import('#compiler').SvelteNode} */ (context.path.at(-1));
const has_action_directive =
parent.type === 'RegularElement' && parent.attributes.find((a) => a.type === 'UseDirective');
// Bindings need to happen after attribute updates, therefore after the render effect, and in order with events/actions. // Bindings need to happen after attribute updates, therefore after the render effect, and in order with events/actions.
// bind:this is a special case as it's one-way and could influence the render effect. // bind:this is a special case as it's one-way and could influence the render effect.
if (node.name === 'this') { if (node.name === 'this') {
state.init.push( state.init.push(b.stmt(call_expr));
b.stmt(has_action_directive ? b.call('$.effect', b.thunk(call_expr)) : call_expr)
);
} else { } else {
const has_action_directive =
parent.type === 'RegularElement' &&
parent.attributes.find((a) => a.type === 'UseDirective');
state.after_update.push( state.after_update.push(
b.stmt(has_action_directive ? b.call('$.effect', b.thunk(call_expr)) : call_expr) b.stmt(has_action_directive ? b.call('$.effect', b.thunk(call_expr)) : call_expr)
); );

@ -22,6 +22,7 @@ export default test({
} }
assert.deepEqual(value, [ assert.deepEqual(value, [
'bind:this true',
'1', '1',
'2', '2',
'3', '3',

@ -1,29 +1,86 @@
<script> <script>
import { onMount } from 'svelte';
export let value = []; export let value = [];
function one(elem) { elem.addEventListener('input', () => { value.push('1'); }); } function one(elem) {
function four(elem) { elem.addEventListener('input', () => { value.push('4'); }); } elem.addEventListener('input', () => {
function eight(elem) { elem.addEventListener('input', () => { value.push('8'); }); } value.push('1');
function twelve(elem) { elem.addEventListener('input', () => { value.push('12'); }); } });
function fifteen(elem) { elem.addEventListener('input', () => { value.push('15'); }); } }
function seventeen(elem) { elem.addEventListener('input', () => { value.push('17'); }); } function four(elem) {
elem.addEventListener('input', () => {
value.push('4');
});
}
function eight(elem) {
elem.addEventListener('input', () => {
value.push('8');
});
}
function twelve(elem) {
elem.addEventListener('input', () => {
value.push('12');
});
}
function fifteen(elem) {
elem.addEventListener('input', () => {
value.push('15');
});
}
function seventeen(elem) {
elem.addEventListener('input', () => {
value.push('17');
});
}
const foo = { const foo = {
set two(v) { value.push('2'); }, set two(v) {
set six(v) { value.push('6'); }, value.push('2');
set nine(v) { value.push('9'); }, },
set eleven(v) { value.push('11'); }, set six(v) {
set thirteen(v) { value.push('13'); }, value.push('6');
set sixteen(v) { value.push('16'); }, },
set nine(v) {
value.push('9');
},
set eleven(v) {
value.push('11');
},
set thirteen(v) {
value.push('13');
},
set sixteen(v) {
value.push('16');
}
};
function three() {
value.push('3');
}
function five() {
value.push('5');
}
function seven() {
value.push('7');
}
function ten() {
value.push('10');
}
function fourteen() {
value.push('14');
}
function eighteen() {
value.push('18');
} }
function three() { value.push('3'); } let el;
function five() { value.push('5'); }
function seven() { value.push('7'); }
function ten() { value.push('10'); }
function fourteen() { value.push('14'); }
function eighteen() { value.push('18'); }
onMount(() => {
// ensure that bind:this doesn't influence the order of directives
// and isn't affected itself by an action being on the element
value.push('bind:this ' + !!el);
});
</script> </script>
<input use:one bind:value={foo.two} on:input={three} /> <input use:one bind:value={foo.two} on:input={three} />
@ -31,4 +88,4 @@
<input on:input={seven} use:eight bind:value={foo.nine} /> <input on:input={seven} use:eight bind:value={foo.nine} />
<input on:input={ten} bind:value={foo.eleven} use:twelve /> <input on:input={ten} bind:value={foo.eleven} use:twelve />
<input bind:value={foo.thirteen} on:input={fourteen} use:fifteen /> <input bind:value={foo.thirteen} on:input={fourteen} use:fifteen />
<input bind:value={foo.sixteen} use:seventeen on:input={eighteen} /> <input bind:this={el} bind:value={foo.sixteen} use:seventeen on:input={eighteen} />

Loading…
Cancel
Save