sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.21k stars 4.09k forks source link

Svelte 5: `{#each expression as name (key)}` behaves differently than Svelte 4 #11232

Closed qupig closed 4 months ago

qupig commented 4 months ago

Describe the bug

{#each expression as name (key)}...{/each}

The issue is that the behavior of key in the above syntax is different in Svelte 4 and 5.

It took a lot of time to lock in to this and make an intuitive minimal reproduction.

Strangely, somehow it couldn't be reproduced in the official Svelte5-REPL, so I had to use StackBlitz to provide an online preview.

You can see in the demo how the actual rendering of the component elements behaves differently when changing the order of the array elements.

Reproduction

StackBlitz-svelte-4.2.15

StackBlitz-svelte-5.0.0-next.108

Svelte5-REPL (Unable to reproduce)

https://github.com/sveltejs/svelte/assets/61939856/2b706191-d133-41eb-94cf-7d6caafcc88f

Logs

No response

System Info

svelte: 5.0.0-next.108

Severity

blocking an upgrade

Thiagolino8 commented 4 months ago

It doesn't happen in the production build, it probably has something to do with HMR

qupig commented 4 months ago

It doesn't happen in the production build, it probably has something to do with HMR

Yes, I can confirm this, which may explain why the issue is not reproduced in Svelte5-REPL.

gterras commented 4 months ago

Can you really use the value itself as a key? I've always thought it was not at all expected but it may be a relic from my Vue days since it isn't mentioned in the docs.

Anyway if you {#each array.entries() as [i, item] (i)} it starts working as expected.

Thiagolino8 commented 4 months ago

Can you really use the value itself as a key? I've always thought it was not at all expected but it may be a relic from my Vue days since it isn't mentioned in the docs.

Yes you can This has always been one of Svelte's differentiators.

The key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change.

gterras commented 4 months ago

Yes you can

Yes although I have trouble seeing what's the under the hood difference in this case VS not using at all a key? Since the keys should also be modified along the values? Worth noting that both repros work as expected without key.

qupig commented 4 months ago

@gterras

Anyway if you {#each array.entries() as [i, item] (i)} it starts working as expected.

No, I tried that version and it produces the same effect. Using the same value is just to simplify reproduction.

I can adapt this to a new reproduction of that syntax if you need it.

Here you go: StackBlitz-svelte-5.0.0-next.108 (with k,v syntax)

Rich-Harris commented 4 months ago

I haven't figured out why, exactly, but this is related to HMR — if I disable it in the Vite config, things work as expected. That's why you can't reproduce it in the REPL

Rich-Harris commented 4 months ago

I tell a lie. HMR is a factor here, insofar as it's what accounts for the discrepancy between repros, but it's actually any effect inside an {#each ...} loop, not just the HMR effect. Remarkable that it wasn't surfaced sooner.

It was introduced in #11197 (demo), and is fixed in #11254.