mirror of https://github.com/sveltejs/svelte
fix: better interop of `$state` with actions/`$:` statements (#10543)
Ensure update methods of actions and reactive statements work with fine-grained `$state` by deep-reading them. This is necessary because mutations to `$state` objects don't notify listeners to only the object as a whole, it only notifies the listeners of the property that changed. fixes #10460 fixes https://github.com/simeydotme/svelte-range-slider-pips/issues/130pull/10553/head
parent
4c9d71f8cf
commit
f5102013af
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"svelte": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: ensure update methods of actions and reactive statements work with fine-grained `$state`
|
@ -0,0 +1,24 @@
|
|||||||
|
import { test } from '../../test';
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
html: `<button>mutate</button><button>reassign</button><div>0</div>`,
|
||||||
|
|
||||||
|
async test({ assert, target }) {
|
||||||
|
const [btn1, btn2] = target.querySelectorAll('button');
|
||||||
|
|
||||||
|
btn1.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`<button>mutate</button><button>reassign</button><div>1</div>`
|
||||||
|
);
|
||||||
|
|
||||||
|
btn2.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`<button>mutate</button><button>reassign</button><div>2</div>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
let foo = $state({ count: 0 });
|
||||||
|
let count = $state(0);
|
||||||
|
|
||||||
|
function action() {
|
||||||
|
return {
|
||||||
|
update(foo) {
|
||||||
|
count = foo.count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button onclick={() => foo.count++}>mutate</button>
|
||||||
|
<button onclick={() => foo = {...foo, count: foo.count + 1 }}>reassign</button>
|
||||||
|
<div use:action={foo}>{count}</div>
|
@ -0,0 +1,24 @@
|
|||||||
|
import { test } from '../../test';
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
html: `<button>reassign</button><button>mutate</button><p>0 / 0</p>`,
|
||||||
|
|
||||||
|
async test({ assert, target }) {
|
||||||
|
const [btn1, btn2] = target.querySelectorAll('button');
|
||||||
|
|
||||||
|
btn1.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`<button>reassign</button><button>mutate</button><p>1 / 1</p>`
|
||||||
|
);
|
||||||
|
|
||||||
|
btn2.click();
|
||||||
|
await tick();
|
||||||
|
assert.htmlEqual(
|
||||||
|
target.innerHTML,
|
||||||
|
`<button>reassign</button><button>mutate</button><p>2 / 2</p>`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
import Old from './old.svelte';
|
||||||
|
|
||||||
|
let prop = $state({ count: 0 });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button onclick={() => prop = {...prop, count: prop.count + 1 }}>reassign</button>
|
||||||
|
<button onclick={() => prop.count++}>mutate</button>
|
||||||
|
<Old {prop}></Old>
|
@ -0,0 +1,11 @@
|
|||||||
|
<svelte:options runes={false} />
|
||||||
|
<script>
|
||||||
|
export let prop;
|
||||||
|
let count_1 = prop.count;
|
||||||
|
$: {
|
||||||
|
count_1 = prop.count;
|
||||||
|
}
|
||||||
|
$: count_2 = prop.count;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>{count_1} / {count_2}</p>
|
Loading…
Reference in new issue