fix: link offscreen items and last effect in each block correctly (alternative) (#17244)

It's possible that due to how new elements are inserted into the array that `effect.last` is wrong. We need to ensure it is really the last item to keep items properly connected to the graph.

Fixes #17201

---------

Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
pull/17245/head
Rich Harris 2 weeks ago committed by GitHub
parent f2dd477031
commit 52a36bdb35
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: link offscreen items and last effect in each block correctly

@ -637,6 +637,10 @@ function link(state, prev, next) {
state.first = next;
state.effect.first = next && next.e;
} else {
if (prev.e === state.effect.last && next !== null) {
state.effect.last = next.e;
}
if (prev.e.next) {
prev.e.next.prev = null;
}
@ -648,6 +652,10 @@ function link(state, prev, next) {
if (next === null) {
state.effect.last = prev && prev.e;
} else {
if (next.e === state.effect.last && prev === null) {
state.effect.last = next.e.prev;
}
if (next.e.prev) {
next.e.prev.next = null;
}

@ -0,0 +1,51 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target }) {
const [add, adjust] = target.querySelectorAll('button');
add.click();
flushSync();
assert.htmlEqual(
target.innerHTML,
`<button>add</button> <button>adjust</button>
<h2>Keyed</h2>
<div>Item: 1. Index: 0</div>
<div>Item: 0. Index: 1</div>
<h2>Unkeyed</h2>
<div>Item: 1. Index: 0</div>
<div>Item: 0. Index: 1</div>`
);
add.click();
flushSync();
assert.htmlEqual(
target.innerHTML,
`<button>add</button> <button>adjust</button>
<h2>Keyed</h2>
<div>Item: 2. Index: 0</div>
<div>Item: 1. Index: 1</div>
<div>Item: 0. Index: 2</div>
<h2>Unkeyed</h2>
<div>Item: 2. Index: 0</div>
<div>Item: 1. Index: 1</div>
<div>Item: 0. Index: 2</div>`
);
adjust.click();
flushSync();
assert.htmlEqual(
target.innerHTML,
`<button>add</button> <button>adjust</button>
<h2>Keyed</h2>
<div>Item: 2. Index: 0</div>
<div>Item: 1. Index: 1</div>
<div>Item: 10. Index: 2</div>
<h2>Unkeyed</h2>
<div>Item: 2. Index: 0</div>
<div>Item: 1. Index: 1</div>
<div>Item: 10. Index: 2</div>`
);
}
});

@ -0,0 +1,16 @@
<script>
const items = $state([{ t: 0 }]);
</script>
<button onclick={() => items.unshift({t:items.length})}>add</button>
<button onclick={() => items.at(-1).t = 10}>adjust</button>
<h2>Keyed</h2>
{#each items as item, index (item)}
<div>Item: {item.t}. Index: {index}</div>
{/each}
<h2>Unkeyed</h2>
{#each items as item, index}
<div>Item: {item.t}. Index: {index}</div>
{/each}
Loading…
Cancel
Save