Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Further explanation of Svelte's keyed each block

I don't understand this section in the tutorial: https://svelte.dev/tutorial/keyed-each-blocks.

I can see the things array is updated correctly so the right thing.color is passed as expected. But by the first sentence "By default, when you modify the value of an each block, it will add and remove items at the end of the block, and update any values that have changed.", it seems to be saying that Svelte anyway removes the last block when clicking the button, then the remaining 4 blocks will be faced with the sliced things, which is

[{ id: 2, color: '#6a00a8' },
 { id: 3, color: '#b12a90' },
 { id: 4, color: '#e16462' },
 { id: 5, color: '#fca636' }]

And since initial is declared as const, it cannot be updated anymore, so the colors of thing.id 1--4 remains.

Is this a correct understanding? Is this default behavior assuming the each blocks are exchangeable?

Then it says using thing.id as the key for the each blocks will solve the issue, namely, {#each things as thing (thing.id)}. I don't understand how the keys are used in the each blocks and what was the default key if thing.id is not provided. And why the default key (if there is one, or the default no-key) doesn't work while providing thing.id does.

Thanks for the clarification.

like image 534
ziyuang Avatar asked Jun 21 '20 13:06

ziyuang


1 Answers

I believe it uses something like the index of the item as the default when you do not provide a key. This can be validated by using

{#each things as thing, index (index)}
    <Thing current={thing.color}/>
{/each}

which gives the same behavior as not using a key in the first place.


Let's call the <Thing> that was rendered for id: 1 as Thing1, and so on.

With no key provided

When we remove the first item from the list, Thing1 still stays the same, because the key (index in this case) associated with it remains the same. The prop that was earlier being sent to Thing2 is now being sent to Thing1. This happens all the way down the chain. But now that there is one less element, Thing5 is removed from the DOM.

The instance of the component Thing that is associated with the key "0" (Thing1) is not destroyed when the first item is removed. This happens because the key stays the same (the new array also has an item at index 0). Only the prop that is being sent to Thing1 has changed, leaving the initial variable with the color of the original item with id: 1.

With (thing.id) key provided

When the thing with id: 1 is removed, there does not exist any instance of Thing which maps to "1". So, Thing1 is removed from the DOM.


Another way to understand is when you give a key, you are essentially telling Svelte to map each rendered block to that very key. When that key doesn't exist anymore, get rid of the block and remove it from the DOM. But if the key stays the same and the props change, update the props instead of recreating the block.

When you don't specify a key, it uses the index of the list as the key. So if you remove items from the list, it won't recreate or reorder the block, it will just update the props.

like image 195
Umang Galaiya Avatar answered Sep 20 '22 17:09

Umang Galaiya