Skip to content

Commit 7c00f1d

Browse files
authored
fix: improve bind:this support around proxyied state (#10732)
* fix: improve bind:this support around proxyied state * fix: improve bind:this support around proxyied state * fix: improve bind:this support around proxyied state
1 parent 304db0d commit 7c00f1d

File tree

6 files changed

+77
-2
lines changed

6 files changed

+77
-2
lines changed

.changeset/blue-ants-raise.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 bind:this support around proxyied state

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ import { run } from '../common.js';
7777
import { bind_transition, trigger_transitions } from './transitions.js';
7878
import { mutable_source, source, set } from './reactivity/sources.js';
7979
import { safe_equal, safe_not_equal } from './reactivity/equality.js';
80+
import { STATE_SYMBOL } from './constants.js';
8081

8182
/** @type {Set<string>} */
8283
const all_registerd_events = new Set();
@@ -1336,6 +1337,17 @@ export function bind_prop(props, prop, value) {
13361337
}
13371338
}
13381339

1340+
/**
1341+
* @param {any} bound_value
1342+
* @param {Element} element_or_component
1343+
* @returns {boolean}
1344+
*/
1345+
function is_bound_this(bound_value, element_or_component) {
1346+
// Find the original target if the value is proxied.
1347+
const proxy_target = bound_value && bound_value[STATE_SYMBOL]?.t;
1348+
return bound_value === element_or_component || proxy_target === element_or_component;
1349+
}
1350+
13391351
/**
13401352
* @param {Element} element_or_component
13411353
* @param {(value: unknown, ...parts: unknown[]) => void} update
@@ -1360,7 +1372,7 @@ export function bind_this(element_or_component, update, get_value, get_parts) {
13601372
update(element_or_component, ...parts);
13611373
// If this is an effect rerun (cause: each block context changes), then nullfiy the binding at
13621374
// the previous position if it isn't already taken over by a different effect.
1363-
if (old_parts && get_value(...old_parts) === element_or_component) {
1375+
if (old_parts && is_bound_this(get_value(...old_parts), element_or_component)) {
13641376
update(null, ...old_parts);
13651377
}
13661378
}
@@ -1374,7 +1386,7 @@ export function bind_this(element_or_component, update, get_value, get_parts) {
13741386
// Defer to the next tick so that all updates can be reconciled first.
13751387
// This solves the case where one variable is shared across multiple this-bindings.
13761388
effect(() => {
1377-
if (get_value(...parts) === element_or_component) {
1389+
if (parts && is_bound_this(get_value(...parts), element_or_component)) {
13781390
update(null, ...parts);
13791391
}
13801392
});
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<script>
2+
export const a = {};
3+
</script>
4+
<div>Hello world</div>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
import { log } from './log.js';
4+
5+
export default test({
6+
before_test: () => {
7+
log.length = 0;
8+
},
9+
10+
html: `<button>Toggle</button><div>Hello\nworld</div>`,
11+
12+
async test({ assert, target }) {
13+
const [btn1] = target.querySelectorAll('button');
14+
15+
flushSync(() => {
16+
btn1?.click();
17+
});
18+
19+
assert.htmlEqual(target.innerHTML, `<button>Toggle</button>`);
20+
21+
flushSync(() => {
22+
btn1?.click();
23+
});
24+
25+
assert.htmlEqual(target.innerHTML, `<button>Toggle</button><div>Hello\nworld</div>`);
26+
27+
assert.deepEqual(log, [{ a: {} }, null, { a: {} }]);
28+
}
29+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/** @type {any[]} */
2+
export const log = [];
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<script>
2+
import { log } from './log.js';
3+
import Component from './Component.svelte';
4+
5+
let type = $state(Component)
6+
let elem = $state()
7+
8+
$effect(() => {
9+
log.push(elem);
10+
});
11+
</script>
12+
13+
<button onclick={() => {
14+
if (!type) {
15+
type = Component
16+
} else {
17+
type = false
18+
}
19+
}}>Toggle</button>
20+
21+
<svelte:component bind:this={elem} this={type}>
22+
Content
23+
</svelte:component>

0 commit comments

Comments
 (0)