Skip to content

Commit d34b1be

Browse files
committed
fix: ensure more bindings run without active context
Continuation of #14194, fixes #15742
1 parent bfb969a commit d34b1be

File tree

5 files changed

+30
-13
lines changed

5 files changed

+30
-13
lines changed

.changeset/strange-rocks-beam.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 more bindings run without active context

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ import { add_form_reset_listener } from '../misc.js';
1212
* then listens to the given events until the render effect context is destroyed
1313
* @param {EventTarget} target
1414
* @param {Array<string>} events
15-
* @param {(event?: Event) => void} handler
15+
* @param {(event?: Event) => void} event_handler
1616
* @param {any} call_handler_immediately
1717
*/
18-
export function listen(target, events, handler, call_handler_immediately = true) {
18+
export function listen(target, events, event_handler, call_handler_immediately = true) {
19+
// Just like user-defined events, our internal events shouldn't have any reactive context
20+
/** @type {typeof event_handler} */
21+
const handler = (e) => without_reactive_context(() => event_handler(e));
22+
1923
if (call_handler_immediately) {
2024
handler();
2125
}
@@ -32,6 +36,9 @@ export function listen(target, events, handler, call_handler_immediately = true)
3236
}
3337

3438
/**
39+
* Runs a function without a reactive context.
40+
* This is important for events which should "start fresh" and not inherit
41+
* context that accidentally happens to be active at the time of the event.
3542
* @template T
3643
* @param {() => T} fn
3744
*/

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,5 @@ export function bind_window_scroll(type, get, set = get) {
6262
* @param {(size: number) => void} set
6363
*/
6464
export function bind_window_size(type, set) {
65-
listen(window, ['resize'], () => without_reactive_context(() => set(window[type])));
65+
listen(window, ['resize'], () => set(window[type]));
6666
}

packages/svelte/tests/runtime-runes/samples/effect-tracking-binding-set/_config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import { test } from '../../test';
22

33
export default test({
44
test({ assert, logs }) {
5-
assert.deepEqual(logs, [false]);
5+
assert.deepEqual(logs, ['bind:activeElement false', 'bind:value false']);
66
}
77
});
Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
<script>
22
let bar = $state('');
33
4-
const foo = {
5-
set bar(v) {
6-
7-
console.log($effect.tracking());
8-
4+
const value = {
5+
set value(v) {
6+
console.log('bind:value ' + $effect.tracking());
97
bar = v;
108
},
11-
get bar() {
9+
get value() {
1210
return bar;
1311
}
14-
}
12+
};
13+
14+
const active = {
15+
set bar(_v) {
16+
console.log('bind:activeElement ' + $effect.tracking());
17+
}
18+
};
1519
1620
let input;
1721
1822
$effect(() => {
1923
input.value = 'everybody';
2024
input.dispatchEvent(new window.Event('input'));
21-
})
25+
});
2226
</script>
2327

24-
<input type="text" bind:value={foo.bar} bind:this={input}>
28+
<svelte:document bind:activeElement={active.bar} />
29+
<input type="text" bind:value={value.value} bind:this={input}>

0 commit comments

Comments
 (0)