Fygo
Fygo

Reputation: 4665

Reactivity of property changes of an object inside of an array

What's the proper way to trigger reactivity in svelte when I am updating a property of an object inside of an array that's then passed as a Component's prop?

let items = [{
   id: 1,
   name: 'first'
}, {
   id: 2,
   name: 'second'
}];

function findItem(id) {
   return items.find(item => item.id == id);
}

function modifyItem(id, changedProps) {
   let item = findItem(id);
   if(item) {
     Object.assign(item, changedProps);
     items = [...items]; // this does nothing
     console.log(items); // correctly displays the modified items array
  }
}

// ...

<MyList {items}/>

So I am passing down my modifyItem function. A child component then calls it and wants to update the items array. That works just fine, but the reactivity is not triggered (I assume because svelte doesn't recognize that an object in the array has been modified) so MyList is never re-rendered.

What's the "proper"/"correct" way of doing this? It seems a bit inefficient to .map the whole array just to create a new instance of the object and push it in. Any other way? Thanks a lot!

Upvotes: 6

Views: 3555

Answers (1)

Andreas Dolk
Andreas Dolk

Reputation: 114757

It should work. Here's a working example. The counter which is a property of an item in the array is incremented as expected.

App.svelte:

<script>
    import DisplayCounter from "./DisplayCounter.svelte";
    let items = [{text: 'hello', count: 0}];

    function incrementCounter() {
      items[0].count++;
      items = [...items];
  }
</script>

<button on:click={incrementCounter}>Click me</button>
<DisplayCounter {items} />

DisplayCounter.svelte:

<script>
    export let items = []
</script>

<div>{items[0].count}</div>

And here's the REPL: https://svelte.dev/repl/9c20112f09284ba983bf598012705c56?version=3.19.1

Upvotes: 1

Related Questions