fix: correctly reconcile each blocks after outroing branches are resumed

pull/17258/head
Rich Harris 1 week ago
parent f9c2b9e6f4
commit e976d40f92

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: correctly reconcile each blocks after outroing branches are resumed

@ -533,11 +533,7 @@ function reconcile(state, array, anchor, flags, get_key) {
stashed = [];
while (current !== null && current.k !== key) {
// If the each block isn't inert and an item has an effect that is already inert,
// skip over adding it to our seen Set as the item is already being handled
if ((current.e.f & INERT) === 0) {
(seen ??= new Set()).add(current);
}
(seen ??= new Set()).add(current);
stashed.push(current);
current = current.next;
}
@ -570,7 +566,15 @@ function reconcile(state, array, anchor, flags, get_key) {
}
if (current !== null || seen !== undefined) {
var to_destroy = seen === undefined ? [] : array_from(seen);
var to_destroy = [];
if (seen !== undefined) {
for (item of seen) {
if ((item.e.f & INERT) === 0) {
to_destroy.push(item);
}
}
}
while (current !== null) {
// If the each block isn't inert, then inert effects are currently outroing and will be removed once the transition is finished

@ -5,11 +5,7 @@ export default test({
async test({ assert, target, raf }) {
const [clear, push] = target.querySelectorAll('button');
raf.tick(0);
flushSync(() => clear.click());
raf.tick(1);
flushSync(() => push.click());
raf.tick(500);

@ -0,0 +1,23 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target, raf }) {
const [clear, reverse] = target.querySelectorAll('button');
flushSync(() => clear.click());
flushSync(() => reverse.click());
raf.tick(1);
assert.htmlEqual(
target.innerHTML,
`
<button>clear</button>
<button>reverse</button>
<span style="opacity: 1;">c</span>
<span style="opacity: 1;">b</span>
<span style="opacity: 1;">a</span>
`
);
}
});

@ -0,0 +1,19 @@
<script>
function fade(node) {
return {
duration: 1000,
tick(t) {
node.style.opacity = t;
}
}
}
let items = $state(['a', 'b', 'c']);
</script>
<button onclick={() => items = []}>clear</button>
<button onclick={() => items = ['c', 'b', 'a']}>reverse</button>
{#each items as item (item)}
<span transition:fade={{duration: 1000}}>{item}</span>
{/each}
Loading…
Cancel
Save