简体   繁体   English

svelte:如何声明两个循环反应变量?

[英]svelte: how can I declare two cyclically reactive variables?

I have two variables a and b which add up to 100. How do I set up a reactive declaration such that when a changes b changes to be 100 - a and vice versa?我有两个变量ab ,它们加起来等于 100。如何设置响应式声明,以便当a更改时b更改为100 - a反之亦然? When I try something like当我尝试类似的东西时

let total = 100;
$: a = total - b;
$: b = total - a;

I get a 'Cyclical dependency detected' error.我收到“检测到循环依赖性”错误。 Is there any way to get this done?有什么办法可以做到这一点?

The problem comes from the fact that Svelte wants to sort the reactive blocks in the order they depend upon each other: it wants to compute those that are depended upon but have no dependencies first, to avoid unneeded computation... or getting trapped in a loop.问题来自这样一个事实,即 Svelte 希望按照它们相互依赖的顺序对反应块进行排序:它希望首先计算那些被依赖但没有依赖关系的块,以避免不必要的计算......或陷入困境环形。

Furthermore, Svelte considers a dependency of a reactive expression any reactive variable that appear in it.此外,Svelte 将反应式表达式的依赖性视为出现在其中的任何反应式变量。

And so, the actual source of your error is that both variables a and b appears in both reactive expressions.因此,错误的实际来源是变量ab都出现在两个反应式表达式中。

The solution is to remove from the reactive expressions the unneeded variable, that is the one that is assigned to.解决方案是从反应式表达式中删除不需要的变量,即分配给的变量。 This can be done by moving the assignment to a function outside of the reactive block.这可以通过将分配移动到反应块之外的 function 来完成。 Unfortunately, it's more verbose...不幸的是,它更冗长......

<script>
    let total = 100;
    let a = 0
    let b = 0
    
    const setA = () => {
        // the assignment to a (or b in the other function) are still
        // reactive, of course, but Svelte won't propagate changes to
        // variable that are assigned their current value, so this
        // will break the loop
        a = total - b
    }
    
    const setB = () => {
        b = total - a
    }
    
    $: setA(total - b);
    $: setB(total - a);
</script>

<pre>
    a: {a}
    b: {b}
</pre>

<label>
    a <input type="number" bind:value={a} />
</label>

<label>
    b <input type="number" bind:value={b} />
</label>

That does not work;那行不通; Svelte does not allow this and this cycle cannot be resolved either. Svelte 不允许这样,这个循环也无法解决。 If you want a variable to be editable, you cannot declare it as reactive ( $: x =... ).如果您希望一个变量是可编辑的,则不能将其声明为反应式( $: x =... )。 You can either reactively set regular variables with reactive statements/blocks or use events instead (see other answers).您可以使用反应性语句/块反应性地设置常规变量,也可以改用事件(请参阅其他答案)。

The following is an explanation why this could not be resolved logically either.下面解释一下为什么这也无法从逻辑上解决。

Treating this like two equations with two unknowns you get this useless simplification:将其视为具有两个未知数的两个方程式,您会得到这种无用的简化:

a = total - b
b = total - a
b = total - (total - b)
b = total - total + b
b = b

You have to fix at least one of the values, otherwise all possible values are valid here.您必须至少修复其中一个值,否则所有可能的值在这里都有效。


You can also first normalize the equations:您还可以先将方程归一化:

a = total - b => a + b = total => a + b = total
b = total - a => b + a = total => a + b = total

As you can see, they are the same, so you actually have two unknowns and only one equation, so this is underspecified.如您所见,它们是相同的,所以您实际上有两个未知数和只有一个方程,所以这是未指定的。

(Note that even if this would yield a valid solution, Svelte cannot solve systems of linear equations for you.) (请注意,即使这会产生有效的解决方案,Svelte 也无法为您求解线性方程组。)

Unless you need the values to update from programmatic changes, i would drop the reactive statements entirely and work with events instead: When one variable is adjusted by the user, update the other one.除非您需要从程序更改中更新值,否则我会完全放弃反应式语句并改为使用事件:当用户调整一个变量时,更新另一个。

<script>
  const total = 100;
  let a = total;
  let b = 0;
</script>

a: {a} <br>
b: {b}

<label>
  a <input type="number" bind:value={a}
           on:input={() => b = total - a} />
</label>

<label>
  b <input type="number" bind:value={b}
           on:input={() => a = total - b} />
</label>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM