I have some strange things happening on my svelte code, here are the simplified version of my code
REPL: https://codesandbox.io/p/devbox/hcfk3l
+page.svelte
<script lang="ts">
import { writable } from 'svelte/store'
import Provider from './provider.svelte'
import Test from './test.svelte'
const sdk = writable<object>({})
sdk.subscribe((v) => console.log('sdk updated:', v))
</script>
<div class="w-full mx-auto max-w-xl">
<h2 class="text-center text-gray-30 uppercase text-c2">Transfer</h2>
<Provider let:values let:val>
<form class="flex flex-col gap-4">
<button
on:click={() => {
console.log('update balance')
values.update((v) => {
return { ...v, balance: 0 }
})
}}>update balance</button>
<button
on:click={() => {
sdk.set({})
}}>update sdk</button>
<Test
func={async () => {
await new Promise((resolve) => setTimeout(resolve, 1500))
console.log('update balance')
values.update((v) => {
return { ...v, balance: 0 }
})
}}
sdk={$sdk} />
</form>
</Provider>
</div>
provider.svelte
<script lang="ts">
import { writable } from 'svelte/store'
const values = writable({})
</script>
<slot {values} val={$values} />
test.svelte
<script lang="ts">
import { onDestroy } from 'svelte'
export let sdk: any
export let func: () => Promise<any>
$: console.log('sdk TEST!', sdk)
$: {
if (sdk) {
func()
}
}
onDestroy(() => {
console.log('destroyed')
})
</script>
Can anyone tell me why when I click on the update sdk
button, the calls flow:
it is weird because the sdk TEST!
is getting called after the update balance
, because in update balance, there is no change to sdk, even the sdk updated
is not getting called.
when I try to call the update balance
using the other button (update balance
button), it doesn't call the sdk TEST!
after the balance update
so why the update balance
call from the func
makes sdk TEST!
getting called, why the update balance
from the button doesn't?
And round and round it goes xD It's a bit hard for me to follow the code execution in my head, but I think the problem is the func
prop in the <Test>
component. When the function in the func
prop is called, then you change the values
store, and I that causes the <Provider>
child to re-render, because in the <Provider>
component you pass its children the prop val={$values}
. So, when values
is a assigned a new value:
<Provider>
component will re-render its child<Test func={...} />
<Test>
is re-rendered, it will change the value in values
I think you can solve the problem by simply skipping the val
prop in the provider.svelte
component. That's the one that causes an unnecessary re-rendering, because you don't use it anyway.