skip to Main Content
<script>
    let count = {value:0};
    const increase = (data)=>{
        console.log(data);
        data = {...data,value: data.value+1};
    }
    const increment = ()=>increase(count);
</script>

<button on:click={increment}>
    Clicked {count.value}
    {count.value === 1 ? 'time' : 'times'}
</button>

I simplified my problem to this code. I have a clojure function that accepts an object and tries to update it. At first, I used the ‘count’ variable as a number but I thought it will not pass the reference so I changed it to an object. But either ways, the count is not change.

2

Answers


  1. You’re just re-assigning the data variable, but to change the count state you need to assign the latest object to the count variable.

    <script>
        let count = { value: 0 };
        
        const increment = () => {
          count = { ...count, value: count.value + 1 }
        }
    </script>
    
    <button on:click={increment}>
        Clicked {count.value}
        {count.value === 1 ? 'time' : 'times'}
    </button>
    
    Login or Signup to reply.
  2. There are two problems with your code

    data = {...data,value: data.value+1};
    

    With this line you are re-assigning a new object to data, removing the reference to the data object you passed in before. So in this case ‘count’ doesn’t change. (You can see this because in successive clicks you keep getting value: 0 in the logs.

    If you change this to

    data.value += 1;
    

    You will be modifying the object you passed in because here you do keep the reference intact. With this code, successive clicks will show that count has changed.

    The markup however will not update because how Svelte works, it will only update if it sees an assignment on the variable, otherwise it has no way (or at least not a performant way) to detect changes to objects. So you have to have somewhere count = ... for Svelte to know that count has updated.

    You can try this by adding

    <button on:click={() => count = count}>Refresh</button>
    

    You will see that when clicking this button it will update the UI.

    A solution might be to rewrite increment to

    const increment = () => {
      increase(count);
      count = count;
    }
    

    Or alternatively, rewrite increase to return the data object and reassign directly

    const increment = () => count = increase(count);
    

    edit for your comment on an answer

    Notice that you can also define an inline function:

    <button on:click={() => count1 = increase(count1)}>
     Clicked {count.value} {count1.value === 1 ? 'time' : 'times'}
    </button>
    <button on:click={() => count2 = increase(count2)}>
     Clicked {count.value} {count2.value === 1 ? 'time' : 'times'}
    </button>
    <button on:click={() => count3 = increase(count3)}>
     Clicked {count.value} {count3.value === 1 ? 'time' : 'times'}
    </button>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search