我错了吗?
是的。不过不要责怪自己,你的期望对我来说似乎是合乎逻辑的。但这不是它的工作方式。
作为一般规则,如果您的组件代码中某处有一个$ 前缀变量,那么它必须是一个商店,它会在组件创建时立即订阅,并取消订阅当组件被销毁时。
最近才引入了此规则的一个小例外(this PR)。如果你想了解整个讨论,我会让你沿着兔子洞的踪迹走。关键在于,现在,商店订阅必须是商店或无效(即null 或undefined——参见this comment) .
这意味着如果需要,现在可以侵入您预期的行为。我们将回到这一点。
如果 canSubscribe 为 false,为什么要订阅 $store?
因为商店是立即订阅的。从上面链接的问题的讨论中,我的理解是,它是为了性能(字节大小)和健全性(如果有人试图订阅不是商店的东西,则会快速而明显地失败)。对我来说很有意义。
现在,回到您没有问的问题:如何仅在需要时/如果需要时订阅?仅在需要时将 store 放入自动订阅的变量中,否则保持为 null。
不要这样做:
$: started && $store
改为这样做:
$: proxyStore = started ? store : null
$: console.log($proxyStore)
完整示例 (REPL):
<script>
import { writable } from 'svelte/store'
const state1 = { subscribed: 0, unsubscribed: 0 }
const store1 = writable(42, () => {
state1.subscribed++
return () => {
state1.unsubscribed++
}
})
const state2 = { subscribed: 0, unsubscribed: 0 }
const store2 = writable(43, () => {
state2.subscribed++
return () => {
state2.unsubscribed++
}
})
let started = false
$: started && $store1
$: targetStore = started ? store2 : null
$: $targetStore
</script>
<pre>
started = {started}
store1 = {$store1} {JSON.stringify(state1)}
store2 = {$targetStore} {JSON.stringify(state2)}
</pre>
<button on:click={() => {started = !started}}>
{started ? 'Start' : 'Stop'}
</button>