skip to Main Content
<script>
    let numbers = [1, 2, 3, 4];
    let obj = {
        foo:{
            bar: "bar"
        }
    }
    function addNumber() {
        numbers.push(numbers.length + 1);
        numbers = numbers;
    }
    
    const changeToBaz = (tempObj) => {
        tempObj.foo.bar = 'bazz';
    }

    $: sum = numbers.reduce((t, n) => t + n, 0);
    $:{
        console.log('sum: ', sum);
        console.log('obj: ', obj);
        changeToBaz(obj);
      }
</script>

<p>{numbers.join(' + ')} = {sum}</p>
<p>{obj.foo.bar}</p>

<button on:click={addNumber}>
    Add a number
</button>

I want to know why the obj.foo.bar is showing bazz ? I am passing the obj state to changeToBaz function and changing the value of bar property. I thought that by changing the value of tempObj.foo.bar will not trigger render as I am not doing obj = tempObj , and I also want to know why in the console the value of obj.foo.bar = "bazz" ,the console is before the calling of changeToBazz function

Here is the screenshot of the page
Page screenshot

3

Answers


  1. Chosen as BEST ANSWER

    I did some digging in reactivity.
 I think the flow is something like this :


    1. let obj = {
            foo:{
                bar: "bar"
            }
        } // causes the reactivity
    
    
    
    2.  $:{
 
            console.log('sum: ', sum);
            console.log('obj: ', obj);
            changeToBaz(obj);
    
          } // since this block is dependent on obj , sum so the 
            // changeToBaz(obj) runs
    
    
    
    3.  const changeToBaz = (tempObj) => {
            tempObj.foo.bar = 'bazz'; //  not causes reactivity but simply  
                                      // changes the bar property value to 
                                      // “bazz”
        }
    
    4.   Since all the reactive statements are done, the component markup is 
        rendered and “bazz” is shown in UI.
    

    Correct me if I am wrong.



  2. I want to know why the obj.foo.bar is showing bazz ?

    To answer this question I trimmed your example to a MCVE and concluded that reactive statements run on page load:

    <script>
        let y = "bar" // equivalent to your `obj` definition
        $: y = "bazz" // equivalent to your $: { changeToBaz(obj) } block
    </script>
    
    {y} <!--- outputs "bazz" - equivalent to your `<p>{obj.foo.bar}</p>` --->
    

    That is, it does not matter whether you made an update to a nested value of the object or not.

    Login or Signup to reply.
  3. The svelte immutable option is false by default so it will trigger reactivity on property changes so long as you tell it the object has changed (as you are doing with numbers = numbers;).

    If you set the immutable option to true (<svelte:options immutable={true}/>) you will see no updates at all because svelte will now only use referential equality to trigger reactivity and since numbers = numbers; passes the same reference a re-render won’t be triggered.

    In both cases bazz is displayed from the very start because all reactive statements are run once before the initial render so while the initial console log of the object will show bar (see below for console caveats) the property will already be set to bazz when the first render takes place.


    The MDN Svelte documentation has more description than the official documentation, see: Advanced Svelte: Reactivity, lifecycle, accessibility

    Here are a few REPLs showing the options:

    Reactivity example (immutable true) (no renders triggered on click)

    Reactivity example (immutable true) forced update (render is forced by assigning a shallow copy numbers = [...numbers];)


    As for the console showing bazz it depends on which console and when you expand the object; objects are often live in the console and only resolve their property values when expanded, since you are calling changeToBaz() directly after the log call there is no opportunity for you to expand it before the value has already been changed. You could log a copy console.log('obj: ', structuredClone(obj)); which would preserve the value at the time of logging. see: Is Chrome’s JavaScript console lazy about evaluating objects?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search