<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
I did some digging in reactivity. I think the flow is something like this :
Correct me if I am wrong.
To answer this question I trimmed your example to a MCVE and concluded that reactive statements run on page load:
That is, it does not matter whether you made an update to a nested value of the object or not.
The svelte
immutable
option isfalse
by default so it will trigger reactivity on property changes so long as you tell it the object has changed (as you are doing withnumbers = 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 sincenumbers = 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 showbar
(see below for console caveats) the property will already be set tobazz
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 callingchangeToBaz()
directly after thelog
call there is no opportunity for you to expand it before the value has already been changed. You could log a copyconsole.log('obj: ', structuredClone(obj));
which would preserve the value at the time of logging. see: Is Chrome’s JavaScript console lazy about evaluating objects?