javascripthtmlsvelterenderrerender

Svelte is not re-rendering


I'm implementing the history component in svelte. It needs to show when the bids array got udpated,

  const bidsArray = [
    { player: 0, bidType: 'pass' },
    { player: 1, bidType: 'level', level: '1', suit: 'NT' },
    { player: 0, bidType: 'level', level: '2', suit: 'NT' },
    { player: 1, bidType: 'level', level: '3', suit: 'S' },
    { player: 0, bidType: 'double' },
    { player: 1, bidType: 'pass' },
  ];
let bidMap = new Map()

let bids = [];
  // Ensure both players are in bidMap from the beginning
  for (let i = 0; i < players.length; i++) {
    const playerIndex = i;
    bidMap.set(playerIndex, []);
  }

  $: {
    bids.forEach((bid) => {
      const { player } = bid;

      if (!bidMap.has(player)) {
        bidMap.set(player, []);
      }

      if (player !== dealer && bidMap.get(player).length === 0) {
        // Add an empty object if the player is not the dealer and the array is empty
        bidMap.get(player).push({});
      }

      bidMap.get(player).push(bid);
    });
  }


 function addBid() {
    console.log("bid called");

    // Check if there are bids in bidsArray
    if (bidsArray.length > 0) {
      // Pop the last element from bidsArray
      const newBid = bidsArray.pop();

      // Update bids using a temporary variable
      bids = [...bids, { ...newBid }];
      bids = bids

    } else {
      console.log("No more bids in bidsArray");
    }
  }

here is my codespace, https://codesandbox.io/p/sandbox/nervous-platform-9hwz5v?file=%2FButton.svelte%3A73%2C15

this is my html code for rendering

<div class="grid-container">
  {#each players as player, playerIndex}
    {#if bidMap.has(playerIndex)}
      <div class="bid-container">
        <div class="player-nickname">{player.nickname}</div>
        {#each bidMap.get(playerIndex) as bid}
          <div
            style="visibility: {getBidText(bid) == null ? 'hidden' : 'auto'}"
            class="bid-text"
          >{getBidText(bid)}</div>
        {/each}
      </div>
    {/if}
  {/each}
</div>

If I click the addBid(), it is not updating the bids array and also the bidMap. How to make it re-render, when the bids array updates.


Solution

  • The reason why the re-rendering was not triggered is that Svelte's reactivity is triggered by assignments, and you tried to modify the bidMap by pushing a new item to the Map, which will not cause any update.

    To make it re-render, you can simply re-assign value to the variable, in your case, the bidMap.

    <script>
    ...
      $: {
        bids.forEach((bid) => {
          const { player } = bid;
    
          if (!bidMap.has(player)) bidMap.set(player, []);
          
          if (player !== dealer && bidMap.get(player).length === 0) bidMap.get(player).push({});
    
          bidMap.get(player).push(bid);
    
          bidMap = bidMap // <- Re-assign the outer "bidMap" to the "bidMap" you just pushed to.
        });
      }
    ...
    </script>
    

    Now you should be able to see the DOM updates.