Svelte 商店有条件的自动订阅
Posted
技术标签:
【中文标题】Svelte 商店有条件的自动订阅【英文标题】:Svelte store conditional auto subscription 【发布时间】:2020-07-29 01:06:52 【问题描述】:复制步骤:
在此处转到 REPL:https://svelte.dev/repl/27a2cff81ebb4000970eee32747cc6c2?version=3.20.1
打开控制台
取消注释第 27 行 ($: canSubscribe && $store
)
预期:
我认为$store
可以订阅(使用$:
)只有如果canSubscribe
为真。
问题是:如果canSubscribe
为假,为什么$store
订阅?
我错了吗?
【问题讨论】:
不要使用代码链接,提供minimal reproducible example 【参考方案1】:Svelte 在编译时遍历 AST 以确定自动订阅。
即使访问商店的代码无法访问,它也会设置订阅。
例如:
import foo from './stores'
let condition = false
if (condition) $foo
尽管$foo
在技术上无法访问,但直到运行时才会知道。
替代方案:您始终可以使用手动订阅来解决此问题。示例:
import onDestroy from 'svelte'
import myStore from './stores.js'
// subscribe when component is created
const unsubscribe = myStore.subscribe(value =>
// this is called anytime the value of myStore changes
)
// make sure to unsubscribe when component is unmounted
onDestroy(unsubscribe)
【讨论】:
@FredHors 我已更新我的答案以包含手动订阅的示例。您可以在此处找到更多详细信息:svelte.dev/tutorial/auto-subscriptions【参考方案2】:我错了吗?
是的。不过不要责怪自己,你的期望对我来说似乎是合乎逻辑的。但这不是它的工作方式。
作为一般规则,如果您的组件代码中某处有一个$
前缀变量,那么它必须是一个商店,它会在组件创建时立即订阅,并取消订阅当组件被销毁时。
最近才引入了此规则的一个小例外(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>
【讨论】:
【参考方案3】:在反应式语句$: canSubscribe && $store
中,您有一个要计算的表达式。由于它是响应式的,因此 Svelte 必须确定何时重新评估此表达式,这将在两种情况下发生:当 canSubscribe
更改时,或者当 $store
更改时。所以它必须对这两个值都进行订阅,因此您会看到您立即在代码中获得订阅者。
请注意,我们经常在 javascript 中使用 canDoSomething && canDoSomething()
,但这与使用 if (canDoSomething) canDoSomething()
并不是 100% 相同,在大多数情况下,效果相同。
【讨论】:
好的。但是,如果我使用if (canSubscribe) $store
,如果canSubscribe
为假,它也会订阅。这是我现在的问题。
是的,只要块中的任何内容发生变化,就会触发反应性。我不确定您首先要实现什么,我的回答只是指出为什么它不能按您的预期工作。以上是关于Svelte 商店有条件的自动订阅的主要内容,如果未能解决你的问题,请参考以下文章