Reputation: 175
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
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