mirror of https://github.com/sveltejs/svelte
fix: avoid unnecessary block effect re-runs after async work completes (#17535)
* add samples for async readable freeze * test updating without changing reference too * fix: treat block effects as maybe dirty in revive() * even simpler - put block effects in maybe_dirty_effects --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>pull/14594/merge
parent
e1427aa0c8
commit
fe12ffc2a3
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: avoid unnecessary block effect re-runs after async work completes
|
||||
@ -0,0 +1,24 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
// ensure in-place object mutations stay reactive in async
|
||||
export default test({
|
||||
skip_no_async: true,
|
||||
async test({ assert, target }) {
|
||||
const button = /** @type {HTMLElement} */ (target.querySelector('button'));
|
||||
|
||||
await tick();
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `<p>count: 1, computed: 10</p><button>mutate</button>`);
|
||||
|
||||
button.click();
|
||||
await tick();
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `<p>count: 2, computed: 20</p><button>mutate</button>`);
|
||||
|
||||
button.click();
|
||||
await tick();
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `<p>count: 3, computed: 30</p><button>mutate</button>`);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,26 @@
|
||||
<script>
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
const data = writable({ count: 1 });
|
||||
|
||||
function mutate_count() {
|
||||
data.update(d => {
|
||||
d.count++;
|
||||
return d;
|
||||
});
|
||||
}
|
||||
|
||||
async function compute(d) {
|
||||
return Promise.resolve(d.count * 10);
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:boundary>
|
||||
<p>count: {$data.count}, computed: {await compute($data)}</p>
|
||||
|
||||
{#snippet pending()}
|
||||
<p>pending</p>
|
||||
{/snippet}
|
||||
</svelte:boundary>
|
||||
|
||||
<button onclick={mutate_count}>mutate</button>
|
||||
@ -0,0 +1,32 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
skip_no_async: true,
|
||||
async test({ assert, target }) {
|
||||
const button = /** @type {HTMLElement} */ (target.querySelector('button'));
|
||||
|
||||
await tick();
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<ul><li data-item="1"><span>10</span><span>20</span></li></ul><button>add</button>`
|
||||
);
|
||||
|
||||
button.click();
|
||||
await tick();
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<ul><li data-item="1"><span>10</span><span>20</span></li><li data-item="2"><span>20</span><span>40</span></li></ul><button>add</button>`
|
||||
);
|
||||
|
||||
button.click();
|
||||
await tick();
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`<ul><li data-item="1"><span>10</span><span>20</span></li><li data-item="2"><span>20</span><span>40</span></li><li data-item="3"><span>30</span><span>60</span></li></ul><button>add</button>`
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,31 @@
|
||||
<script>
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
const items = writable([{ id: 1 }]);
|
||||
|
||||
function add_item() {
|
||||
items.update(arr => [...arr, { id: arr.length + 1 }]);
|
||||
}
|
||||
|
||||
function query(item) {
|
||||
return Promise.resolve([item.id * 10, item.id * 20]);
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:boundary>
|
||||
<ul>
|
||||
{#each $items as item (item.id)}
|
||||
<li data-item={item.id}>
|
||||
{#each await query(item) as value}
|
||||
<span>{value}</span>
|
||||
{/each}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
{#snippet pending()}
|
||||
<p>pending</p>
|
||||
{/snippet}
|
||||
</svelte:boundary>
|
||||
|
||||
<button onclick={add_item}>add</button>
|
||||
Loading…
Reference in new issue