Skip to content

Commit 0b4c67c

Browse files
committed
fix: ensure bind_checked defers mutation to ensure reactive graph stability
1 parent 6f03561 commit 0b4c67c

File tree

5 files changed

+71
-3
lines changed

5 files changed

+71
-3
lines changed

.changeset/happy-eggs-rest.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: ensure bind_checked defers mutation to ensure reactive graph stability

packages/svelte/src/internal/client/dom/elements/bindings/input.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,14 @@ export function bind_checked(input, get, set = get) {
180180
set(value);
181181
});
182182

183-
if (get() == undefined) {
184-
set(false);
185-
}
183+
// We defer setting the value as we might already be in an active
184+
// block like an each block where that effect hasn't yet hooked up
185+
// to the reactivity graph
186+
queue_micro_task(() => {
187+
if (get() == undefined) {
188+
set(false);
189+
}
190+
});
186191

187192
render_effect(() => {
188193
var value = get();
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
async test({ assert, target }) {
6+
const button = target.querySelector('button');
7+
8+
button?.click();
9+
flushSync();
10+
11+
assert.htmlEqual(
12+
target.innerHTML,
13+
`<button>Add</button><label><input type="checkbox">\n1</label><label><input type="checkbox">\nfoo</label>`
14+
)
15+
}
16+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script>
2+
let { value = $bindable(), config } = $props();
3+
</script>
4+
5+
<label>
6+
<input type="checkbox" bind:checked={value} />
7+
{config.title}
8+
</label>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<script>
2+
import Checkbox from './checkbox.svelte';
3+
4+
let foo = $state({})
5+
6+
const schema = $state({
7+
properties: {
8+
foo: true,
9+
},
10+
})
11+
12+
function retrieveSchema(schema, value) {
13+
const cloned = { ...schema, properties: { ...schema.properties } }
14+
for (const key of Object.keys(value)) {
15+
cloned.properties[key] = key
16+
}
17+
return cloned
18+
}
19+
20+
const retrieved = $derived(retrieveSchema(schema, foo));
21+
const required = $derived(new Set(retrieved.required));
22+
const properties = $derived(retrieved.properties);
23+
const keys = $derived(Object.keys(properties));
24+
let nextKey = 1;
25+
</script>
26+
27+
<button onclick={() => {
28+
foo[nextKey++] = true
29+
}}>Add</button>
30+
31+
{#each keys as key (key)}
32+
{@const config = { title: key, required: required.has(key) }}
33+
<Checkbox bind:value={foo[key]} {config} />
34+
{/each}

0 commit comments

Comments
 (0)