Przemek
Przemek

Reputation: 175

Svelte store: values updated in forEach loop are not updated dynamically (still changed though)

Minimal working example is here:

Repl: https://svelte.dev/repl/ed0fb480159849458c2878d2210e9a40

Code:

App.svelte:

<script>
    import { array } from './store.js';
    import Child from './Child.svelte'
    
    
    function classicLoop() {
    for (let i=0;i<$array.length; i++) {
        $array[i].value ++
    }
    }
    
    function forEachLoop() {
    let i = 0
        $array.forEach(el => {
        el.value ++;
        console.log('loop element:',el);
        console.log('store element:',$array[i]);
        i++
    })
    }
</script>

<button on:click={classicLoop}>
    Classic loop
</button>
<button on:click={forEachLoop}>
    ForEach loop
</button>
<p>
    Items:
</p>
{#each $array as item}

<Child {item} />
{/each}

Child.svelte:

<script>
export let item;
</script>
<p>
    {item.id} -- {item.value}
</p>

store.js:

import { writable } from 'svelte/store';

export const array = writable([{id:'first',value:1},{id:'second',value:2},{id:'third',value:3}]);

Problem: When looping using Array.forEach inside Svelte Store, values are updated (logged to console to be sure), but dynamic binding does not work and changes are not visible in DOM (values are still changed in the store though). Classic loop works fine. So, after using forEach nothing is visible, but then using classic loop updates DOM to current (proper) values.

So, I might of course stick to classic loop, but I'd like to understand what is going on here, and why :)

Any comment/hints appreciated.

Upvotes: 0

Views: 1702

Answers (1)

Geoff Rich
Geoff Rich

Reputation: 5472

Svelte's reactivity is triggered by assignment. In the classic for loop, you directly assign to $array[i].value, and Svelte updates the DOM accordingly. In the forEach, you assign to the intermediate variable el. Svelte does not know that setting el is actually setting $array[i], so it does not trigger an update.

You can add an assignment to $array at the end of your function to force Svelte to update.

function forEachLoop() {
    $array.forEach(el => {
        el.value ++;
    });
    $array = $array;
}

Upvotes: 4

Related Questions