Skip to content

Commit d793d57

Browse files
authored
fix: improve consistency issues around binding invalidation (#9810)
* co * Add comment
1 parent 01a2117 commit d793d57

File tree

6 files changed

+47
-1
lines changed

6 files changed

+47
-1
lines changed

.changeset/soft-clocks-remember.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: improve consistency issues around binding invalidation

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ function setup_select_synchronization(value_binding, context) {
245245
context.state.init.push(
246246
b.stmt(
247247
b.call(
248-
'$.pre_effect',
248+
'$.invalidate_effect',
249249
b.thunk(
250250
b.block([
251251
b.stmt(

packages/svelte/src/internal/client/runtime.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,17 @@ export function pre_effect(init) {
12731273
);
12741274
}
12751275

1276+
/**
1277+
* This effect is used to ensure binding are kept in sync. We use a pre effect to ensure we run before the
1278+
* bindings which are in later effects. However, we don't use a pre_effect directly as we don't want to flush anything.
1279+
*
1280+
* @param {() => void | (() => void)} init
1281+
* @returns {import('./types.js').EffectSignal}
1282+
*/
1283+
export function invalidate_effect(init) {
1284+
return internal_create_effect(PRE_EFFECT, init, true, current_block, true);
1285+
}
1286+
12761287
/**
12771288
* @param {() => void | (() => void)} init
12781289
* @returns {import('./types.js').EffectSignal}

packages/svelte/src/internal/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export {
1212
user_effect,
1313
render_effect,
1414
pre_effect,
15+
invalidate_effect,
1516
flushSync,
1617
bubble_event,
1718
safe_equal,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
async test({ assert, target }) {
5+
assert.htmlEqual(target.innerHTML, 'a\n<select></select><button>change</button');
6+
7+
const [b1] = target.querySelectorAll('button');
8+
b1.click();
9+
await Promise.resolve();
10+
11+
assert.htmlEqual(
12+
target.innerHTML,
13+
'a\n<select></select>b\n<select></select><button>change</button'
14+
);
15+
}
16+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
let entries = $state([{selected: 'a'}])
3+
</script>
4+
5+
{#each entries as entry}
6+
{entry.selected} <select bind:value={entry.selected}></select>
7+
{/each}
8+
9+
<button
10+
on:click={
11+
() => entries = [{selected: 'a'}, {selected: 'b'}]
12+
}
13+
>change</button>

0 commit comments

Comments
 (0)