Home > database >  Is this a problem with Array push() in Svelte or is it something I'm doing wrong?
Is this a problem with Array push() in Svelte or is it something I'm doing wrong?

Time:11-11

I've been wracking my brain over this issue for several hours now, and although I've found a workaround to the problem, I can't get over the fact that it's happening at all. I don't understand it. There seems to be some sort of an issue in using Array.push() within a promise handler. I've created the below test code to demonstrate it, and it's reproducable in Svelte REPL. Am I just doing something wrong?

<script>
  const myPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('foo');
    }, 300);
  });

  let itemsA = [];
  let itemsB = [];

  const addItem = (item) => {
    itemsA[itemsA.length] = item;
    itemsB.push(item);
  }
    
  const loadItems = (last) => {
    addItem("Begin");

    myPromise
      .then((value) => {
        addItem(value);
      });

    addItem("End");
    return true;
  };

  loadItems();
</script>

<div>Items A: {itemsA}</div>
<div>Items B: {itemsB}</div>

I would think that itemsB.push(item) should do the same thing as itemsA[itemsA.length] = item, and it does, except when called from inside the promise handler.

I get the following results instead:

Items A: Begin,End,foo
Items B: Begin,End

Edit: I've eliminated promises as the source of the weirdness. The following code illustrates it more simply.

<script>
  let itemsA = [];
  let itemsB = [];

  const addItem = (item) => {
    itemsA[itemsA.length] = item;
    itemsB.push(item);
  }

    const clickHandler = () => {
        addItem('click');
    }
    
    addItem('load');
</script>

<div>Items A: {itemsA}</div>
<div>Items B: {itemsB}</div>
<button on:click={clickHandler}>Click Me</button>

CodePudding user response:

Actually that has nothing to do with the promise. When you add a button and log the arrays, you see that 'foo' is in 'itemsB' as well, it's just not rendered. From the Svelte Docs

Because Svelte's reactivity is based on assignments, using array methods like .push() and .splice() won't automatically trigger updates. A subsequent assignment is required to trigger the update.
The according tutorial

You can use .push() if it's followed by a reassignment of the array to itself

itemsB.push(item);
itemsB = itemsB

or alternatively use the spread operator syntax

itemsB = [...itemsB, item]

Here's a REPL to try this out

  • Related