When having an #each block in svelte (like https://learn.svelte.dev/tutorial/keyed-each-blocks), the entry is only updated if the content changed. This works perfectly in the tutorials example, where a string is given as property to a nested component:
{#each things as thing (thing.id)}
<Thing name={thing.name}/>
{/each}
But if I give the whole object (thing) and adjust Thing accordingly, it always updates all list entries. Hence I wonder what the condition is Svelte decides on, whether to update the component or not. Is it the property, which is incase of the whole object a reference and therefore always changes? Or is the whole Nested component generated to be compared against the DOM? Is it bad practice to give an Object to a component?
App.svelte
<script>
import Thing from './Thing.svelte';
let things = [
{ id: 1, name: 'apple' },
{ id: 2, name: 'banana' },
{ id: 3, name: 'carrot' },
{ id: 4, name: 'doughnut' },
{ id: 5, name: 'egg' }
];
function handleClick() {
things = things.slice(1);
}
</script>
<button on:click={handleClick}>
Remove first thing
</button>
{#each things as thing (thing.id)}
<Thing name={thing} />
{/each}
Thing.svelte
<script>
import {
beforeUpdate,
afterUpdate
} from 'svelte';
const emojis = {
apple: '🍎',
banana: '🍌',
carrot: '🥕',
doughnut: '🍩',
egg: '🥚'
};
export let name;
const emoji = emojis[name.name];
beforeUpdate(() => {
console.log('before updating ' + name.id)
});
afterUpdate(() => {
console.log('after updating ' + name.id)
});
</script>
<p>{emoji} = {name.name}</p>
The update lifecycle functions are called everytime, even if the content didn't change.
Edit: With the REPL there is this JS output tab which I searched a little. There are many of these p() {...} like:
p(ctx, [dirty]) {
if (dirty & /*name*/ 1 && t2_value !== (t2_value = /*name*/ ctx[0].name + "")) set_data(t2, t2_value);
},
which seem to do the job. The one above is the one from the Thing create_fragment return. To me, the comparison seems good, but still an update is done.