如何在不与 svelte 中的编译器作斗争的情况下避免循环依赖?

hgl*_*hgl 7 javascript reactive-programming svelte

我正在阅读文档,在调整了它的示例代码之后,我设法让编译器向我咆哮,说循环依赖是这样的:

<script>
    let count = 0;
    $: double = count * 2;

    $: if (double >= 20) {
        alert(`count is dangerously high!`);
        count = 9;
    }

    function handleClick() {
        count += 1;
    }
</script>

<button on:click={handleClick}>
    Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
Run Code Online (Sandbox Code Playgroud)

我在 discord 上询问如何修复它,人们建议我应该像这样对编译器隐藏依赖项:

<script>
    let count = 0;
    $: double = count * 2;

    function resetCount() {
        count = 9;
    }

    $: if (double >= 20) {
        alert(`count is dangerously high!`);
        resetCount();
    }

    function handleClick() {
        count += 1;
    }
</script>

<button on:click={handleClick}>
    Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
Run Code Online (Sandbox Code Playgroud)

它有效,但我有几个问题:

  1. 与编译器作斗争对我来说听起来不合适,还有其​​他更好的方法来解决这个问题吗?
  2. 一个更普遍的问题是,循环依赖是否经常发生在编写大量 svelte 代码的人身上?这是正常的还是通常表明设计不佳?

谢谢。

Jos*_*son 6

@morphyish sort-of 的答案提供了一个解决方案,因为正如他们所说:

反应式语句不能触发自身

但是,我认为这有点技术性,并且仍然认为提供的解决方案在概念上具有循环依赖性:我们仍然有count -> double -> count -> ....

因为我们通过将语句合并到一个反应块中来绕过这个循环依赖警告,我们实际上还引入了一个错误:

在此处输入图片说明

发生此错误是因为该double10 * 2在反应块的开头设置为= 20,然后在 if 语句中count设置为9,但由于反应块不会再次触发double而未设置回9 * 2 = 18

我对此的建议以及类似的情况是重新评估您的依赖项实际上是什么,以消除这些循环:

double = count * 2;
Run Code Online (Sandbox Code Playgroud)

^ 所以double取决于count,这很容易。

if (double >= 20) {
  alert('count is dangerously high!');
  count = 9;
}
Run Code Online (Sandbox Code Playgroud)

^ 乍一看,我们的计数重置逻辑似乎取决于double,但正如我们已经建立的那样,double取决于count,并且该块最终与 相关count,该逻辑实际上取决于count而不是 double

所以在我看来,最好的解决方案是修改条件以匹配实际依赖:

<script>
    let count = 0;
    $: double = count * 2;

    $: if (count >= 10) {
        alert(`count is dangerously high!`);
        count = 9;
    }

    function handleClick() {
        count += 1;
    }
</script>

<button on:click={handleClick}>
    Clicked {count} {count === 1 ? 'time' : 'times'}
</button>

Run Code Online (Sandbox Code Playgroud)


Mor*_*ish 3

您可以通过稍微不同地组织代码来解决此问题:

<script>
    let count = 0;
    let double;
    $: {
       double = count * 2;
       if (double >= 20) {
        alert(`count is dangerously high!`);
        count = 9;
       }
    }

    function handleClick() {
        count += 1;
    }
</script>

<button on:click={handleClick}>
    Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
Run Code Online (Sandbox Code Playgroud)

您可以使用一个小警告将反应式语句组合在一起{}:Svelte 不会像其他情况那样自动编写变量声明。

我以前从未遇到过这个问题,但就您而言,这两个语句似乎都依赖于count更新,尽管是间接更新第二个语句。因此,将它们实际上分组为一个语句是有意义的。

它还解决了您的问题,因为反应性语句无法自行触发。

然而,这意味着如果您还想更新,double则需要明确地进行更新。