fix: handle component binding mutation (#10786)

* fix: handle component binding mutation

https://github.com/sveltejs/svelte/issues/10359#issuecomment-1991885046

* alternative approach to mutating props (#10788)

Co-authored-by: Rich Harris <rich.harris@vercel.com>

---------

Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/10782/head
Simon H 1 year ago committed by GitHub
parent 2cb78ac253
commit 339782f3e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: handle component binding mutation

@ -470,12 +470,14 @@ export function serialize_set_binding(node, context, fallback, options) {
if (binding.kind === 'prop') { if (binding.kind === 'prop') {
return b.call( return b.call(
left, left,
b.assignment( b.sequence([
node.operator, b.assignment(
/** @type {import('estree').Pattern} */ (visit(node.left)), node.operator,
value /** @type {import('estree').Pattern} */ (visit(node.left)),
), value
b.literal(true) ),
b.call(left)
])
); );
} else { } else {
return b.call( return b.call(

@ -210,7 +210,7 @@ export function prop(props, key, flags, initial) {
if (!immutable) current_value.equals = safe_equals; if (!immutable) current_value.equals = safe_equals;
return function (/** @type {V} */ value, mutation = false) { return function (/** @type {V} */ value) {
var current = get(current_value); var current = get(current_value);
// legacy nonsense — need to ensure the source is invalidated when necessary // legacy nonsense — need to ensure the source is invalidated when necessary
@ -226,9 +226,9 @@ export function prop(props, key, flags, initial) {
} }
if (arguments.length > 0) { if (arguments.length > 0) {
if (mutation || (immutable ? value !== current : safe_not_equal(value, current))) { if (!current_value.equals(value)) {
from_child = true; from_child = true;
set(inner_current_value, mutation ? current : value); set(inner_current_value, value);
get(current_value); // force a synchronisation immediately get(current_value); // force a synchronisation immediately
} }

@ -0,0 +1,5 @@
<script>
export let value;
</script>
<input bind:value={value.name}>

@ -0,0 +1,32 @@
import { ok, test } from '../../test';
export default test({
html: `
<input>
<p>foo</p>
`,
ssrHtml: `
<input value=foo>
<p>foo</p>
`,
async test({ assert, component, target, window }) {
const event = new window.MouseEvent('input');
const input = target.querySelector('input');
ok(input);
input.value = 'blah';
await input.dispatchEvent(event);
await Promise.resolve();
assert.deepEqual(component.deep, { name: 'blah' });
assert.htmlEqual(
target.innerHTML,
`
<input>
<p>blah</p>
`
);
}
});

@ -0,0 +1,11 @@
<script>
import Widget from './Widget.svelte';
export let deep = {
name: 'foo'
};
</script>
<Widget bind:value={deep}/>
<p>{deep.name}</p>
Loading…
Cancel
Save