diff --git a/.changeset/blue-ants-raise.md b/.changeset/blue-ants-raise.md new file mode 100644 index 000000000000..b77e70216ddb --- /dev/null +++ b/.changeset/blue-ants-raise.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: improve bind:this support around proxyied state diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 0fc26d3e3483..75c361d7a9ef 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -77,6 +77,7 @@ import { run } from '../common.js'; import { bind_transition, trigger_transitions } from './transitions.js'; import { mutable_source, source, set } from './reactivity/sources.js'; import { safe_equal, safe_not_equal } from './reactivity/equality.js'; +import { STATE_SYMBOL } from './constants.js'; /** @type {Set} */ const all_registerd_events = new Set(); @@ -1336,6 +1337,17 @@ export function bind_prop(props, prop, value) { } } +/** + * @param {any} bound_value + * @param {Element} element_or_component + * @returns {boolean} + */ +function is_bound_this(bound_value, element_or_component) { + // Find the original target if the value is proxied. + const proxy_target = bound_value && bound_value[STATE_SYMBOL]?.t; + return bound_value === element_or_component || proxy_target === element_or_component; +} + /** * @param {Element} element_or_component * @param {(value: unknown, ...parts: unknown[]) => void} update @@ -1360,7 +1372,7 @@ export function bind_this(element_or_component, update, get_value, get_parts) { update(element_or_component, ...parts); // If this is an effect rerun (cause: each block context changes), then nullfiy the binding at // the previous position if it isn't already taken over by a different effect. - if (old_parts && get_value(...old_parts) === element_or_component) { + if (old_parts && is_bound_this(get_value(...old_parts), element_or_component)) { update(null, ...old_parts); } } @@ -1374,7 +1386,7 @@ export function bind_this(element_or_component, update, get_value, get_parts) { // Defer to the next tick so that all updates can be reconciled first. // This solves the case where one variable is shared across multiple this-bindings. effect(() => { - if (get_value(...parts) === element_or_component) { + if (parts && is_bound_this(get_value(...parts), element_or_component)) { update(null, ...parts); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/Component.svelte b/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/Component.svelte new file mode 100644 index 000000000000..4e3f2d6c0a99 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/Component.svelte @@ -0,0 +1,4 @@ + +
Hello world
diff --git a/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/_config.js b/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/_config.js new file mode 100644 index 000000000000..e075b5a5888d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/_config.js @@ -0,0 +1,29 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { log } from './log.js'; + +export default test({ + before_test: () => { + log.length = 0; + }, + + html: `
Hello\nworld
`, + + async test({ assert, target }) { + const [btn1] = target.querySelectorAll('button'); + + flushSync(() => { + btn1?.click(); + }); + + assert.htmlEqual(target.innerHTML, ``); + + flushSync(() => { + btn1?.click(); + }); + + assert.htmlEqual(target.innerHTML, `
Hello\nworld
`); + + assert.deepEqual(log, [{ a: {} }, null, { a: {} }]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/log.js b/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/log.js new file mode 100644 index 000000000000..d3df521f4da7 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/log.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const log = []; diff --git a/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/main.svelte b/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/main.svelte new file mode 100644 index 000000000000..adc67f46aee5 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/bind-this-proxy/main.svelte @@ -0,0 +1,23 @@ + + + + + + Content +